Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2012 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 "ui/views/controls/tree/tree_view.h" | 5 #include "ui/views/controls/tree/tree_view.h" |
| 6 | 6 |
| 7 #include <algorithm> | 7 #include <algorithm> |
| 8 | 8 |
| 9 #include "base/i18n/rtl.h" | 9 #include "base/i18n/rtl.h" |
| 10 #include "base/message_loop/message_loop.h" | 10 #include "base/message_loop/message_loop.h" |
| 11 #include "ui/accessibility/ax_view_state.h" | 11 #include "ui/accessibility/ax_view_state.h" |
| 12 #include "ui/base/ime/input_method.h" | 12 #include "ui/base/ime/input_method.h" |
| 13 #include "ui/base/resource/resource_bundle.h" | 13 #include "ui/base/resource/resource_bundle.h" |
| 14 #include "ui/events/event.h" | 14 #include "ui/events/event.h" |
| 15 #include "ui/events/keycodes/keyboard_codes.h" | 15 #include "ui/events/keycodes/keyboard_codes.h" |
| 16 #include "ui/gfx/canvas.h" | 16 #include "ui/gfx/canvas.h" |
| 17 #include "ui/gfx/geometry/rect.h" | 17 #include "ui/gfx/geometry/rect.h" |
| 18 #include "ui/gfx/geometry/rect_conversions.h" | 18 #include "ui/gfx/geometry/rect_conversions.h" |
| 19 #include "ui/gfx/image/image.h" | 19 #include "ui/gfx/image/image.h" |
| 20 #include "ui/gfx/skia_util.h" | 20 #include "ui/gfx/skia_util.h" |
| 21 #include "ui/native_theme/native_theme.h" | 21 #include "ui/native_theme/native_theme.h" |
| 22 #include "ui/resources/grit/ui_resources.h" | 22 #include "ui/resources/grit/ui_resources.h" |
| 23 #include "ui/views/controls/prefix_selector.h" | 23 #include "ui/views/controls/prefix_selector.h" |
| 24 #include "ui/views/controls/scroll_view.h" | 24 #include "ui/views/controls/scroll_view.h" |
| 25 #include "ui/views/controls/textfield/textfield.h" | 25 #include "ui/views/controls/textfield/textfield.h" |
| 26 #include "ui/views/controls/tree/tree_view_controller.h" | 26 #include "ui/views/controls/tree/tree_view_controller.h" |
| 27 #include "ui/views/resources/grit/views_resources.h" | 27 #include "ui/views/resources/grit/views_resources.h" |
| 28 #include "ui/views/style/platform_style.h" | |
| 28 | 29 |
| 29 using ui::TreeModel; | 30 using ui::TreeModel; |
| 30 using ui::TreeModelNode; | 31 using ui::TreeModelNode; |
| 31 | 32 |
| 32 namespace views { | 33 namespace views { |
| 33 | 34 |
| 34 // Insets around the view. | 35 // Insets around the view. |
| 35 static const int kHorizontalInset = 2; | 36 static const int kHorizontalInset = 2; |
| 36 static const int kVerticalInset = 2; | 37 static const int kVerticalInset = 2; |
| 37 // Padding before/after the image. | 38 // Padding before/after the image. |
| (...skipping 23 matching lines...) Expand all Loading... | |
| 61 // and |is_selected| is true if the item is selected. | 62 // and |is_selected| is true if the item is selected. |
| 62 ui::NativeTheme::ColorId text_color_id(bool has_focus, bool is_selected) { | 63 ui::NativeTheme::ColorId text_color_id(bool has_focus, bool is_selected) { |
| 63 if (is_selected) { | 64 if (is_selected) { |
| 64 if (has_focus) | 65 if (has_focus) |
| 65 return ui::NativeTheme::kColorId_TreeSelectedText; | 66 return ui::NativeTheme::kColorId_TreeSelectedText; |
| 66 return ui::NativeTheme::kColorId_TreeSelectedTextUnfocused; | 67 return ui::NativeTheme::kColorId_TreeSelectedTextUnfocused; |
| 67 } | 68 } |
| 68 return ui::NativeTheme::kColorId_TreeText; | 69 return ui::NativeTheme::kColorId_TreeText; |
| 69 } | 70 } |
| 70 | 71 |
| 72 bool EventIsDoubleTapOrClick(const ui::LocatedEvent& event) { | |
| 73 if (event.type() == ui::ET_GESTURE_TAP) | |
| 74 return event.AsGestureEvent()->details().tap_count() == 2; | |
| 75 return event.flags() & ui::EF_IS_DOUBLE_CLICK; | |
| 76 } | |
| 77 | |
| 71 } // namespace | 78 } // namespace |
| 72 | 79 |
| 73 TreeView::TreeView() | 80 TreeView::TreeView() |
| 74 : model_(NULL), | 81 : model_(NULL), |
| 75 selected_node_(NULL), | 82 selected_node_(NULL), |
| 76 editing_(false), | 83 editing_(false), |
| 77 editor_(NULL), | 84 editor_(NULL), |
| 78 focus_manager_(NULL), | 85 focus_manager_(NULL), |
| 79 auto_expand_children_(false), | 86 auto_expand_children_(false), |
| 80 editable_(true), | 87 editable_(true), |
| (...skipping 155 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 236 SchedulePaintForNode(selected_node_); | 243 SchedulePaintForNode(selected_node_); |
| 237 selected_node_ = node; | 244 selected_node_ = node; |
| 238 if (selected_node_ == &root_ && !root_shown_) | 245 if (selected_node_ == &root_ && !root_shown_) |
| 239 selected_node_ = NULL; | 246 selected_node_ = NULL; |
| 240 if (selected_node_ && selected_node_ != &root_) | 247 if (selected_node_ && selected_node_ != &root_) |
| 241 Expand(model_->GetParent(selected_node_->model_node())); | 248 Expand(model_->GetParent(selected_node_->model_node())); |
| 242 SchedulePaintForNode(selected_node_); | 249 SchedulePaintForNode(selected_node_); |
| 243 } | 250 } |
| 244 | 251 |
| 245 if (selected_node_) | 252 if (selected_node_) |
| 246 ScrollRectToVisible(GetBoundsForNode(selected_node_)); | 253 ScrollRectToVisible(GetForegroundBoundsForNode(selected_node_)); |
| 247 | 254 |
| 248 // Notify controller if the old selection was empty to handle the case of | 255 // Notify controller if the old selection was empty to handle the case of |
| 249 // remove explicitly resetting selected_node_ before invoking this. | 256 // remove explicitly resetting selected_node_ before invoking this. |
| 250 if (controller_ && (changed || was_empty_selection)) | 257 if (controller_ && (changed || was_empty_selection)) |
| 251 controller_->OnTreeViewSelectionChanged(this); | 258 controller_->OnTreeViewSelectionChanged(this); |
| 252 | 259 |
| 253 if (changed) { | 260 if (changed) { |
| 254 NotifyAccessibilityEvent(ui::AX_EVENT_TEXT_CHANGED, true); | 261 NotifyAccessibilityEvent(ui::AX_EVENT_TEXT_CHANGED, true); |
| 255 NotifyAccessibilityEvent(ui::AX_EVENT_SELECTION, true); | 262 NotifyAccessibilityEvent(ui::AX_EVENT_SELECTION, true); |
| 256 } | 263 } |
| (...skipping 128 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 385 | 392 |
| 386 void TreeView::ShowContextMenu(const gfx::Point& p, | 393 void TreeView::ShowContextMenu(const gfx::Point& p, |
| 387 ui::MenuSourceType source_type) { | 394 ui::MenuSourceType source_type) { |
| 388 if (!model_) | 395 if (!model_) |
| 389 return; | 396 return; |
| 390 if (source_type == ui::MENU_SOURCE_MOUSE) { | 397 if (source_type == ui::MENU_SOURCE_MOUSE) { |
| 391 // Only invoke View's implementation (which notifies the | 398 // Only invoke View's implementation (which notifies the |
| 392 // ContextMenuController) if over a node. | 399 // ContextMenuController) if over a node. |
| 393 gfx::Point local_point(p); | 400 gfx::Point local_point(p); |
| 394 ConvertPointFromScreen(this, &local_point); | 401 ConvertPointFromScreen(this, &local_point); |
| 395 int row = (local_point.y() - kVerticalInset) / row_height_; | 402 if (!NodeAtPoint(local_point)) |
| 396 int depth = 0; | |
| 397 InternalNode* node = GetNodeByRow(row, &depth); | |
| 398 if (!node) | |
| 399 return; | |
| 400 gfx::Rect bounds(GetBoundsForNodeImpl(node, row, depth)); | |
| 401 if (!bounds.Contains(local_point)) | |
| 402 return; | 403 return; |
| 403 } | 404 } |
| 404 View::ShowContextMenu(p, source_type); | 405 View::ShowContextMenu(p, source_type); |
| 405 } | 406 } |
| 406 | 407 |
| 407 void TreeView::GetAccessibleState(ui::AXViewState* state) { | 408 void TreeView::GetAccessibleState(ui::AXViewState* state) { |
| 408 state->role = ui::AX_ROLE_TREE; | 409 state->role = ui::AX_ROLE_TREE; |
| 409 state->AddStateFlag(ui::AX_STATE_READ_ONLY); | 410 state->AddStateFlag(ui::AX_STATE_READ_ONLY); |
| 410 if (!selected_node_) | 411 if (!selected_node_) |
| 411 return; | 412 return; |
| (...skipping 114 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 526 SetSelectedNode(GetNodeForRow(row)); | 527 SetSelectedNode(GetNodeForRow(row)); |
| 527 } | 528 } |
| 528 | 529 |
| 529 base::string16 TreeView::GetTextForRow(int row) { | 530 base::string16 TreeView::GetTextForRow(int row) { |
| 530 return GetNodeForRow(row)->GetTitle(); | 531 return GetNodeForRow(row)->GetTitle(); |
| 531 } | 532 } |
| 532 | 533 |
| 533 gfx::Point TreeView::GetKeyboardContextMenuLocation() { | 534 gfx::Point TreeView::GetKeyboardContextMenuLocation() { |
| 534 int y = height() / 2; | 535 int y = height() / 2; |
| 535 if (selected_node_) { | 536 if (selected_node_) { |
| 536 gfx::Rect node_bounds(GetBoundsForNode(selected_node_)); | 537 gfx::Rect node_bounds(GetForegroundBoundsForNode(selected_node_)); |
| 537 gfx::Rect vis_bounds(GetVisibleBounds()); | 538 gfx::Rect vis_bounds(GetVisibleBounds()); |
| 538 if (node_bounds.y() >= vis_bounds.y() && | 539 if (node_bounds.y() >= vis_bounds.y() && |
| 539 node_bounds.y() < vis_bounds.bottom()) { | 540 node_bounds.y() < vis_bounds.bottom()) { |
| 540 y = node_bounds.y(); | 541 y = node_bounds.y(); |
| 541 } | 542 } |
| 542 } | 543 } |
| 543 gfx::Point screen_loc(0, y); | 544 gfx::Point screen_loc(0, y); |
| 544 if (base::i18n::IsRTL()) | 545 if (base::i18n::IsRTL()) |
| 545 screen_loc.set_x(width()); | 546 screen_loc.set_x(width()); |
| 546 ConvertPointToScreen(this, &screen_loc); | 547 ConvertPointToScreen(this, &screen_loc); |
| (...skipping 86 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 633 GetInputMethod()->DetachTextInputClient(GetPrefixSelector()); | 634 GetInputMethod()->DetachTextInputClient(GetPrefixSelector()); |
| 634 SchedulePaintForNode(selected_node_); | 635 SchedulePaintForNode(selected_node_); |
| 635 if (selector_) | 636 if (selector_) |
| 636 selector_->OnViewBlur(); | 637 selector_->OnViewBlur(); |
| 637 } | 638 } |
| 638 | 639 |
| 639 bool TreeView::OnClickOrTap(const ui::LocatedEvent& event) { | 640 bool TreeView::OnClickOrTap(const ui::LocatedEvent& event) { |
| 640 CommitEdit(); | 641 CommitEdit(); |
| 641 RequestFocus(); | 642 RequestFocus(); |
| 642 | 643 |
| 643 int row = (event.y() - kVerticalInset) / row_height_; | 644 InternalNode* node = NodeAtPoint(event.location()); |
| 644 int depth = 0; | 645 if (!node) |
| 645 InternalNode* node = GetNodeByRow(row, &depth); | 646 return true; |
| 646 if (node) { | 647 |
| 647 gfx::Rect bounds(GetBoundsForNodeImpl(node, row, depth)); | 648 bool hits_arrow = HitsNodeArrow(node, event.location()); |
| 648 if (bounds.Contains(event.location())) { | 649 if (!hits_arrow) |
| 649 int relative_x = event.x() - bounds.x(); | 650 SetSelectedNode(node->model_node()); |
| 650 if (base::i18n::IsRTL()) | 651 |
| 651 relative_x = bounds.width() - relative_x; | 652 if (hits_arrow || EventIsDoubleTapOrClick(event)) { |
| 652 if (relative_x < kArrowRegionSize && | 653 if (node->is_expanded()) |
| 653 model_->GetChildCount(node->model_node())) { | 654 Collapse(node->model_node()); |
| 654 if (node->is_expanded()) | 655 else |
| 655 Collapse(node->model_node()); | 656 Expand(node->model_node()); |
| 656 else | |
| 657 Expand(node->model_node()); | |
| 658 } else if (relative_x > kArrowRegionSize) { | |
| 659 SetSelectedNode(node->model_node()); | |
| 660 bool should_toggle = false; | |
| 661 if (event.type() == ui::ET_GESTURE_TAP) { | |
| 662 const ui::GestureEvent& gesture = | |
| 663 static_cast<const ui::GestureEvent&>(event); | |
| 664 should_toggle = gesture.details().tap_count() == 2; | |
| 665 } else { | |
| 666 should_toggle = (event.flags() & ui::EF_IS_DOUBLE_CLICK) != 0; | |
| 667 } | |
| 668 if (should_toggle) { | |
| 669 if (node->is_expanded()) | |
| 670 Collapse(node->model_node()); | |
| 671 else | |
| 672 Expand(node->model_node()); | |
| 673 } | |
| 674 } | |
| 675 } | |
| 676 } | 657 } |
| 677 return true; | 658 return true; |
| 678 } | 659 } |
| 679 | 660 |
| 680 void TreeView::LoadChildren(InternalNode* node) { | 661 void TreeView::LoadChildren(InternalNode* node) { |
| 681 DCHECK_EQ(0, node->child_count()); | 662 DCHECK_EQ(0, node->child_count()); |
| 682 DCHECK(!node->loaded_children()); | 663 DCHECK(!node->loaded_children()); |
| 683 node->set_loaded_children(true); | 664 node->set_loaded_children(true); |
| 684 for (int i = 0, child_count = model_->GetChildCount(node->model_node()); | 665 for (int i = 0, child_count = model_->GetChildCount(node->model_node()); |
| 685 i < child_count; ++i) { | 666 i < child_count; ++i) { |
| (...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 718 kTextHorizontalPadding * 2, | 699 kTextHorizontalPadding * 2, |
| 719 row_height_ * GetRowCount() + kVerticalInset * 2); | 700 row_height_ * GetRowCount() + kVerticalInset * 2); |
| 720 } | 701 } |
| 721 | 702 |
| 722 void TreeView::LayoutEditor() { | 703 void TreeView::LayoutEditor() { |
| 723 if (!editing_) | 704 if (!editing_) |
| 724 return; | 705 return; |
| 725 | 706 |
| 726 DCHECK(selected_node_); | 707 DCHECK(selected_node_); |
| 727 // Position the editor so that its text aligns with the text we drew. | 708 // Position the editor so that its text aligns with the text we drew. |
| 728 gfx::Rect row_bounds = GetBoundsForNode(selected_node_); | 709 gfx::Rect row_bounds = GetForegroundBoundsForNode(selected_node_); |
| 729 row_bounds.set_x( | 710 row_bounds.set_x( |
| 730 GetMirroredXWithWidthInView(row_bounds.x(), row_bounds.width())); | 711 GetMirroredXWithWidthInView(row_bounds.x(), row_bounds.width())); |
| 731 row_bounds.set_x(row_bounds.x() + text_offset_); | 712 row_bounds.set_x(row_bounds.x() + text_offset_); |
| 732 row_bounds.set_width(row_bounds.width() - text_offset_); | 713 row_bounds.set_width(row_bounds.width() - text_offset_); |
| 733 row_bounds.Inset(kTextHorizontalPadding, kTextVerticalPadding); | 714 row_bounds.Inset(kTextHorizontalPadding, kTextVerticalPadding); |
| 734 row_bounds.Inset(-empty_editor_size_.width() / 2, | 715 row_bounds.Inset(-empty_editor_size_.width() / 2, |
| 735 -(empty_editor_size_.height() - font_list_.GetHeight()) / 2); | 716 -(empty_editor_size_.height() - font_list_.GetHeight()) / 2); |
| 736 // Give a little extra space for editing. | 717 // Give a little extra space for editing. |
| 737 row_bounds.set_width(row_bounds.width() + 50); | 718 row_bounds.set_width(row_bounds.width() + 50); |
| 738 editor_->SetBoundsRect(row_bounds); | 719 editor_->SetBoundsRect(row_bounds); |
| 739 editor_->Layout(); | 720 editor_->Layout(); |
| 740 } | 721 } |
| 741 | 722 |
| 742 void TreeView::SchedulePaintForNode(InternalNode* node) { | 723 void TreeView::SchedulePaintForNode(InternalNode* node) { |
| 743 if (!node) | 724 if (!node) |
| 744 return; // Explicitly allow NULL to be passed in. | 725 return; // Explicitly allow NULL to be passed in. |
| 745 SchedulePaintInRect(GetBoundsForNode(node)); | 726 SchedulePaintInRect(GetBackgroundBoundsForNode(node)); |
| 746 } | 727 } |
| 747 | 728 |
| 748 void TreeView::PaintRows(gfx::Canvas* canvas, | 729 void TreeView::PaintRows(gfx::Canvas* canvas, |
| 749 int min_row, | 730 int min_row, |
| 750 int max_row, | 731 int max_row, |
| 751 InternalNode* node, | 732 InternalNode* node, |
| 752 int depth, | 733 int depth, |
| 753 int* row) { | 734 int* row) { |
| 754 if (*row >= max_row) | 735 if (*row >= max_row) |
| 755 return; | 736 return; |
| 756 | 737 |
| 757 if (*row >= min_row && *row < max_row) | 738 if (*row >= min_row && *row < max_row) |
| 758 PaintRow(canvas, node, *row, depth); | 739 PaintRow(canvas, node, *row, depth); |
| 759 (*row)++; | 740 (*row)++; |
| 760 if (!node->is_expanded()) | 741 if (!node->is_expanded()) |
| 761 return; | 742 return; |
| 762 depth++; | 743 depth++; |
| 763 for (int i = 0; i < node->child_count() && *row < max_row; ++i) | 744 for (int i = 0; i < node->child_count() && *row < max_row; ++i) |
| 764 PaintRows(canvas, min_row, max_row, node->GetChild(i), depth, row); | 745 PaintRows(canvas, min_row, max_row, node->GetChild(i), depth, row); |
| 765 } | 746 } |
| 766 | 747 |
| 767 void TreeView::PaintRow(gfx::Canvas* canvas, | 748 void TreeView::PaintRow(gfx::Canvas* canvas, |
| 768 InternalNode* node, | 749 InternalNode* node, |
| 769 int row, | 750 int row, |
| 770 int depth) { | 751 int depth) { |
| 771 gfx::Rect bounds(GetBoundsForNodeImpl(node, row, depth)); | 752 gfx::Rect bounds(GetForegroundBoundsForNodeImpl(node, row, depth)); |
| 753 const SkColor selected_row_bg_color = GetNativeTheme()->GetSystemColor( | |
| 754 text_background_color_id(HasFocus() || editing_)); | |
| 755 | |
| 756 // Paint the row background. | |
| 757 if (PlatformStyle::kTreeViewSelectsEntireRow && selected_node_ == node) | |
| 758 canvas->FillRect(GetBackgroundBoundsForNode(node), selected_row_bg_color); | |
| 772 | 759 |
| 773 if (model_->GetChildCount(node->model_node())) | 760 if (model_->GetChildCount(node->model_node())) |
| 774 PaintExpandControl(canvas, bounds, node->is_expanded()); | 761 PaintExpandControl(canvas, bounds, node->is_expanded()); |
| 775 | 762 |
| 776 // Paint the icon. | 763 // Paint the icon. |
| 777 gfx::ImageSkia icon; | 764 gfx::ImageSkia icon; |
| 778 int icon_index = model_->GetIconIndex(node->model_node()); | 765 int icon_index = model_->GetIconIndex(node->model_node()); |
| 779 if (icon_index != -1) | 766 if (icon_index != -1) |
| 780 icon = icons_[icon_index]; | 767 icon = icons_[icon_index]; |
| 781 else if (node == selected_node_) | 768 else if (node == selected_node_) |
| 782 icon = open_icon_; | 769 icon = open_icon_; |
| 783 else | 770 else |
| 784 icon = closed_icon_; | 771 icon = closed_icon_; |
| 785 int icon_x = kArrowRegionSize + kImagePadding + | 772 int icon_x = kArrowRegionSize + kImagePadding + |
| 786 (open_icon_.width() - icon.width()) / 2; | 773 (open_icon_.width() - icon.width()) / 2; |
| 787 if (base::i18n::IsRTL()) | 774 if (base::i18n::IsRTL()) |
| 788 icon_x = bounds.right() - icon_x - open_icon_.width(); | 775 icon_x = bounds.right() - icon_x - open_icon_.width(); |
| 789 else | 776 else |
| 790 icon_x += bounds.x(); | 777 icon_x += bounds.x(); |
| 791 canvas->DrawImageInt( | 778 canvas->DrawImageInt( |
| 792 icon, icon_x, | 779 icon, icon_x, |
| 793 bounds.y() + (bounds.height() - icon.height()) / 2); | 780 bounds.y() + (bounds.height() - icon.height()) / 2); |
| 794 | 781 |
| 795 if (!editing_ || node != selected_node_) { | 782 // Paint the text background and text. In edit mode, the selected node is a |
| 796 gfx::Rect text_bounds(bounds.x() + text_offset_, bounds.y(), | 783 // separate editing control, so it does not need to be painted here. |
| 797 bounds.width() - text_offset_, bounds.height()); | 784 if (editing_ && selected_node_ == node) |
| 798 if (base::i18n::IsRTL()) | 785 return; |
| 799 text_bounds.set_x(bounds.x()); | 786 |
| 800 if (node == selected_node_) { | 787 gfx::Rect text_bounds(GetTextBoundsForNode(node)); |
| 801 const SkColor bg_color = GetNativeTheme()->GetSystemColor( | 788 if (base::i18n::IsRTL()) |
| 802 text_background_color_id(HasFocus())); | 789 text_bounds.set_x(bounds.x()); |
| 803 canvas->FillRect(text_bounds, bg_color); | 790 |
| 804 if (HasFocus()) | 791 // Paint the background on the selected row. |
| 805 canvas->DrawFocusRect(text_bounds); | 792 if (!PlatformStyle::kTreeViewSelectsEntireRow && node == selected_node_) { |
| 806 } | 793 canvas->FillRect(text_bounds, selected_row_bg_color); |
| 807 const ui::NativeTheme::ColorId color_id = | 794 if (HasFocus()) |
| 808 text_color_id(HasFocus(), node == selected_node_); | 795 canvas->DrawFocusRect(text_bounds); |
| 809 const gfx::Rect internal_bounds( | |
| 810 text_bounds.x() + kTextHorizontalPadding, | |
| 811 text_bounds.y() + kTextVerticalPadding, | |
| 812 text_bounds.width() - kTextHorizontalPadding * 2, | |
| 813 text_bounds.height() - kTextVerticalPadding * 2); | |
| 814 canvas->DrawStringRect(node->model_node()->GetTitle(), font_list_, | |
| 815 GetNativeTheme()->GetSystemColor(color_id), | |
| 816 internal_bounds); | |
| 817 } | 796 } |
| 797 | |
| 798 // Paint the text. | |
| 799 const ui::NativeTheme::ColorId color_id = | |
| 800 text_color_id(HasFocus(), node == selected_node_); | |
| 801 const gfx::Rect internal_bounds( | |
| 802 text_bounds.x() + kTextHorizontalPadding, | |
| 803 text_bounds.y() + kTextVerticalPadding, | |
| 804 text_bounds.width() - kTextHorizontalPadding * 2, | |
| 805 text_bounds.height() - kTextVerticalPadding * 2); | |
| 806 canvas->DrawStringRect(node->model_node()->GetTitle(), font_list_, | |
| 807 GetNativeTheme()->GetSystemColor(color_id), | |
| 808 internal_bounds); | |
| 818 } | 809 } |
| 819 | 810 |
| 820 void TreeView::PaintExpandControl(gfx::Canvas* canvas, | 811 void TreeView::PaintExpandControl(gfx::Canvas* canvas, |
| 821 const gfx::Rect& node_bounds, | 812 const gfx::Rect& node_bounds, |
| 822 bool expanded) { | 813 bool expanded) { |
| 823 int center_x; | 814 int center_x; |
| 824 if (base::i18n::IsRTL()) { | 815 if (base::i18n::IsRTL()) { |
| 825 center_x = node_bounds.right() - kArrowRegionSize + | 816 center_x = node_bounds.right() - kArrowRegionSize + |
| 826 (kArrowRegionSize - 4) / 2; | 817 (kArrowRegionSize - 4) / 2; |
| 827 } else { | 818 } else { |
| (...skipping 30 matching lines...) Expand all Loading... | |
| 858 return NULL; | 849 return NULL; |
| 859 if (!parent_internal_node->loaded_children()) { | 850 if (!parent_internal_node->loaded_children()) { |
| 860 if (create_type == DONT_CREATE_IF_NOT_LOADED) | 851 if (create_type == DONT_CREATE_IF_NOT_LOADED) |
| 861 return NULL; | 852 return NULL; |
| 862 LoadChildren(parent_internal_node); | 853 LoadChildren(parent_internal_node); |
| 863 } | 854 } |
| 864 return parent_internal_node->GetChild( | 855 return parent_internal_node->GetChild( |
| 865 model_->GetIndexOf(parent_internal_node->model_node(), model_node)); | 856 model_->GetIndexOf(parent_internal_node->model_node(), model_node)); |
| 866 } | 857 } |
| 867 | 858 |
| 868 gfx::Rect TreeView::GetBoundsForNode(InternalNode* node) { | 859 gfx::Rect TreeView::GetBackgroundBoundsForNode(InternalNode* node) { |
| 860 if (!PlatformStyle::kTreeViewSelectsEntireRow) | |
| 861 return GetForegroundBoundsForNode(node); | |
| 862 | |
| 863 int row, ignored_depth; | |
| 864 row = GetRowForInternalNode(node, &ignored_depth); | |
| 865 return gfx::Rect(bounds().x(), row * row_height_ + kVerticalInset, | |
| 866 bounds().width(), row_height_); | |
| 867 } | |
| 868 | |
| 869 gfx::Rect TreeView::GetForegroundBoundsForNode(InternalNode* node) { | |
| 869 int row, depth; | 870 int row, depth; |
| 870 row = GetRowForInternalNode(node, &depth); | 871 row = GetRowForInternalNode(node, &depth); |
| 871 return GetBoundsForNodeImpl(node, row, depth); | 872 return GetForegroundBoundsForNodeImpl(node, row, depth); |
| 872 } | 873 } |
| 873 | 874 |
| 874 gfx::Rect TreeView::GetBoundsForNodeImpl(InternalNode* node, | 875 gfx::Rect TreeView::GetTextBoundsForNode(InternalNode* node) { |
| 875 int row, | 876 gfx::Rect bounds(GetForegroundBoundsForNode(node)); |
| 876 int depth) { | 877 bounds.Inset(text_offset_, 0, 0, 0); |
| 878 return bounds; | |
| 879 } | |
| 880 | |
| 881 gfx::Rect TreeView::GetForegroundBoundsForNodeImpl(InternalNode* node, | |
| 882 int row, | |
| 883 int depth) { | |
| 877 gfx::Rect rect(depth * kIndent + kHorizontalInset, | 884 gfx::Rect rect(depth * kIndent + kHorizontalInset, |
| 878 row * row_height_ + kVerticalInset, | 885 row * row_height_ + kVerticalInset, |
| 879 text_offset_ + node->text_width() + | 886 text_offset_ + node->text_width() + |
| 880 kTextHorizontalPadding * 2, | 887 kTextHorizontalPadding * 2, |
| 881 row_height_); | 888 row_height_); |
| 882 rect.set_x(GetMirroredXWithWidthInView(rect.x(), rect.width())); | 889 rect.set_x(GetMirroredXWithWidthInView(rect.x(), rect.width())); |
| 883 return rect; | 890 return rect; |
| 884 } | 891 } |
| 885 | 892 |
| 886 int TreeView::GetRowForInternalNode(InternalNode* node, int* depth) { | 893 int TreeView::GetRowForInternalNode(InternalNode* node, int* depth) { |
| (...skipping 117 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1004 } | 1011 } |
| 1005 return return_value; | 1012 return return_value; |
| 1006 } | 1013 } |
| 1007 | 1014 |
| 1008 PrefixSelector* TreeView::GetPrefixSelector() { | 1015 PrefixSelector* TreeView::GetPrefixSelector() { |
| 1009 if (!selector_) | 1016 if (!selector_) |
| 1010 selector_.reset(new PrefixSelector(this)); | 1017 selector_.reset(new PrefixSelector(this)); |
| 1011 return selector_.get(); | 1018 return selector_.get(); |
| 1012 } | 1019 } |
| 1013 | 1020 |
| 1021 TreeView::InternalNode* TreeView::NodeAtPoint(const gfx::Point& point) { | |
| 1022 int row = (point.y() - kVerticalInset) / row_height_; | |
| 1023 int depth = -1; | |
| 1024 InternalNode* node = GetNodeByRow(row, &depth); | |
| 1025 if (!node) | |
| 1026 return nullptr; | |
| 1027 | |
| 1028 // If the entire row gets a selected background, clicking anywhere in the row | |
| 1029 // serves to hit this node. | |
| 1030 if (PlatformStyle::kTreeViewSelectsEntireRow) | |
| 1031 return node; | |
| 1032 gfx::Rect bounds(GetForegroundBoundsForNodeImpl(node, row, depth)); | |
| 1033 return bounds.Contains(point) ? node : nullptr; | |
| 1034 } | |
| 1035 | |
| 1036 bool TreeView::HitsNodeArrow(InternalNode* node, const gfx::Point& point) { | |
| 1037 if (!model_->GetChildCount(node->model_node())) | |
| 1038 return false; | |
| 1039 | |
| 1040 int depth = -1; | |
| 1041 int row = GetRowForInternalNode(node, &depth); | |
|
sky
2016/06/16 17:34:39
Can this use GetForegroundBoundsForNode? It would
Elly Fong-Jones
2016/06/23 19:47:13
I don't think so. This function needs to use row a
| |
| 1042 | |
| 1043 int arrow_dx = depth * kIndent + kHorizontalInset; | |
| 1044 gfx::Rect arrow_bounds(bounds().x() + arrow_dx, | |
| 1045 row * row_height_ + kVerticalInset, kArrowRegionSize, | |
| 1046 row_height_); | |
| 1047 if (base::i18n::IsRTL()) | |
| 1048 arrow_bounds.set_x(bounds().width() - arrow_dx - kArrowRegionSize); | |
| 1049 return arrow_bounds.Contains(point); | |
| 1050 } | |
| 1051 | |
| 1014 // InternalNode ---------------------------------------------------------------- | 1052 // InternalNode ---------------------------------------------------------------- |
| 1015 | 1053 |
| 1016 TreeView::InternalNode::InternalNode() | 1054 TreeView::InternalNode::InternalNode() |
| 1017 : model_node_(NULL), | 1055 : model_node_(NULL), |
| 1018 loaded_children_(false), | 1056 loaded_children_(false), |
| 1019 is_expanded_(false), | 1057 is_expanded_(false), |
| 1020 text_width_(0) { | 1058 text_width_(0) { |
| 1021 } | 1059 } |
| 1022 | 1060 |
| 1023 TreeView::InternalNode::~InternalNode() { | 1061 TreeView::InternalNode::~InternalNode() { |
| (...skipping 20 matching lines...) Expand all Loading... | |
| 1044 if (!is_expanded_) | 1082 if (!is_expanded_) |
| 1045 return max_width; | 1083 return max_width; |
| 1046 for (int i = 0; i < child_count(); ++i) { | 1084 for (int i = 0; i < child_count(); ++i) { |
| 1047 max_width = std::max(max_width, | 1085 max_width = std::max(max_width, |
| 1048 GetChild(i)->GetMaxWidth(indent, depth + 1)); | 1086 GetChild(i)->GetMaxWidth(indent, depth + 1)); |
| 1049 } | 1087 } |
| 1050 return max_width; | 1088 return max_width; |
| 1051 } | 1089 } |
| 1052 | 1090 |
| 1053 } // namespace views | 1091 } // namespace views |
| OLD | NEW |