| 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 (!GetNodeAtPoint(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 117 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 529 SetSelectedNode(GetNodeForRow(row)); | 530 SetSelectedNode(GetNodeForRow(row)); |
| 530 } | 531 } |
| 531 | 532 |
| 532 base::string16 TreeView::GetTextForRow(int row) { | 533 base::string16 TreeView::GetTextForRow(int row) { |
| 533 return GetNodeForRow(row)->GetTitle(); | 534 return GetNodeForRow(row)->GetTitle(); |
| 534 } | 535 } |
| 535 | 536 |
| 536 gfx::Point TreeView::GetKeyboardContextMenuLocation() { | 537 gfx::Point TreeView::GetKeyboardContextMenuLocation() { |
| 537 int y = height() / 2; | 538 int y = height() / 2; |
| 538 if (selected_node_) { | 539 if (selected_node_) { |
| 539 gfx::Rect node_bounds(GetBoundsForNode(selected_node_)); | 540 gfx::Rect node_bounds(GetForegroundBoundsForNode(selected_node_)); |
| 540 gfx::Rect vis_bounds(GetVisibleBounds()); | 541 gfx::Rect vis_bounds(GetVisibleBounds()); |
| 541 if (node_bounds.y() >= vis_bounds.y() && | 542 if (node_bounds.y() >= vis_bounds.y() && |
| 542 node_bounds.y() < vis_bounds.bottom()) { | 543 node_bounds.y() < vis_bounds.bottom()) { |
| 543 y = node_bounds.y(); | 544 y = node_bounds.y(); |
| 544 } | 545 } |
| 545 } | 546 } |
| 546 gfx::Point screen_loc(0, y); | 547 gfx::Point screen_loc(0, y); |
| 547 if (base::i18n::IsRTL()) | 548 if (base::i18n::IsRTL()) |
| 548 screen_loc.set_x(width()); | 549 screen_loc.set_x(width()); |
| 549 ConvertPointToScreen(this, &screen_loc); | 550 ConvertPointToScreen(this, &screen_loc); |
| (...skipping 86 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 636 GetInputMethod()->DetachTextInputClient(GetPrefixSelector()); | 637 GetInputMethod()->DetachTextInputClient(GetPrefixSelector()); |
| 637 SchedulePaintForNode(selected_node_); | 638 SchedulePaintForNode(selected_node_); |
| 638 if (selector_) | 639 if (selector_) |
| 639 selector_->OnViewBlur(); | 640 selector_->OnViewBlur(); |
| 640 } | 641 } |
| 641 | 642 |
| 642 bool TreeView::OnClickOrTap(const ui::LocatedEvent& event) { | 643 bool TreeView::OnClickOrTap(const ui::LocatedEvent& event) { |
| 643 CommitEdit(); | 644 CommitEdit(); |
| 644 RequestFocus(); | 645 RequestFocus(); |
| 645 | 646 |
| 646 int row = (event.y() - kVerticalInset) / row_height_; | 647 InternalNode* node = GetNodeAtPoint(event.location()); |
| 647 int depth = 0; | 648 if (!node) |
| 648 InternalNode* node = GetNodeByRow(row, &depth); | 649 return true; |
| 649 if (node) { | 650 |
| 650 gfx::Rect bounds(GetBoundsForNodeImpl(node, row, depth)); | 651 bool hits_arrow = IsPointInExpandControl(node, event.location()); |
| 651 if (bounds.Contains(event.location())) { | 652 if (!hits_arrow) |
| 652 int relative_x = event.x() - bounds.x(); | 653 SetSelectedNode(node->model_node()); |
| 653 if (base::i18n::IsRTL()) | 654 |
| 654 relative_x = bounds.width() - relative_x; | 655 if (hits_arrow || EventIsDoubleTapOrClick(event)) { |
| 655 if (relative_x < kArrowRegionSize && | 656 if (node->is_expanded()) |
| 656 model_->GetChildCount(node->model_node())) { | 657 Collapse(node->model_node()); |
| 657 if (node->is_expanded()) | 658 else |
| 658 Collapse(node->model_node()); | 659 Expand(node->model_node()); |
| 659 else | |
| 660 Expand(node->model_node()); | |
| 661 } else if (relative_x > kArrowRegionSize) { | |
| 662 SetSelectedNode(node->model_node()); | |
| 663 bool should_toggle = false; | |
| 664 if (event.type() == ui::ET_GESTURE_TAP) { | |
| 665 const ui::GestureEvent& gesture = | |
| 666 static_cast<const ui::GestureEvent&>(event); | |
| 667 should_toggle = gesture.details().tap_count() == 2; | |
| 668 } else { | |
| 669 should_toggle = (event.flags() & ui::EF_IS_DOUBLE_CLICK) != 0; | |
| 670 } | |
| 671 if (should_toggle) { | |
| 672 if (node->is_expanded()) | |
| 673 Collapse(node->model_node()); | |
| 674 else | |
| 675 Expand(node->model_node()); | |
| 676 } | |
| 677 } | |
| 678 } | |
| 679 } | 660 } |
| 680 return true; | 661 return true; |
| 681 } | 662 } |
| 682 | 663 |
| 683 void TreeView::LoadChildren(InternalNode* node) { | 664 void TreeView::LoadChildren(InternalNode* node) { |
| 684 DCHECK_EQ(0, node->child_count()); | 665 DCHECK_EQ(0, node->child_count()); |
| 685 DCHECK(!node->loaded_children()); | 666 DCHECK(!node->loaded_children()); |
| 686 node->set_loaded_children(true); | 667 node->set_loaded_children(true); |
| 687 for (int i = 0, child_count = model_->GetChildCount(node->model_node()); | 668 for (int i = 0, child_count = model_->GetChildCount(node->model_node()); |
| 688 i < child_count; ++i) { | 669 i < child_count; ++i) { |
| (...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 721 kTextHorizontalPadding * 2, | 702 kTextHorizontalPadding * 2, |
| 722 row_height_ * GetRowCount() + kVerticalInset * 2); | 703 row_height_ * GetRowCount() + kVerticalInset * 2); |
| 723 } | 704 } |
| 724 | 705 |
| 725 void TreeView::LayoutEditor() { | 706 void TreeView::LayoutEditor() { |
| 726 if (!editing_) | 707 if (!editing_) |
| 727 return; | 708 return; |
| 728 | 709 |
| 729 DCHECK(selected_node_); | 710 DCHECK(selected_node_); |
| 730 // Position the editor so that its text aligns with the text we drew. | 711 // Position the editor so that its text aligns with the text we drew. |
| 731 gfx::Rect row_bounds = GetBoundsForNode(selected_node_); | 712 gfx::Rect row_bounds = GetForegroundBoundsForNode(selected_node_); |
| 732 row_bounds.set_x( | 713 row_bounds.set_x( |
| 733 GetMirroredXWithWidthInView(row_bounds.x(), row_bounds.width())); | 714 GetMirroredXWithWidthInView(row_bounds.x(), row_bounds.width())); |
| 734 row_bounds.set_x(row_bounds.x() + text_offset_); | 715 row_bounds.set_x(row_bounds.x() + text_offset_); |
| 735 row_bounds.set_width(row_bounds.width() - text_offset_); | 716 row_bounds.set_width(row_bounds.width() - text_offset_); |
| 736 row_bounds.Inset(kTextHorizontalPadding, kTextVerticalPadding); | 717 row_bounds.Inset(kTextHorizontalPadding, kTextVerticalPadding); |
| 737 row_bounds.Inset(-empty_editor_size_.width() / 2, | 718 row_bounds.Inset(-empty_editor_size_.width() / 2, |
| 738 -(empty_editor_size_.height() - font_list_.GetHeight()) / 2); | 719 -(empty_editor_size_.height() - font_list_.GetHeight()) / 2); |
| 739 // Give a little extra space for editing. | 720 // Give a little extra space for editing. |
| 740 row_bounds.set_width(row_bounds.width() + 50); | 721 row_bounds.set_width(row_bounds.width() + 50); |
| 741 editor_->SetBoundsRect(row_bounds); | 722 editor_->SetBoundsRect(row_bounds); |
| 742 editor_->Layout(); | 723 editor_->Layout(); |
| 743 } | 724 } |
| 744 | 725 |
| 745 void TreeView::SchedulePaintForNode(InternalNode* node) { | 726 void TreeView::SchedulePaintForNode(InternalNode* node) { |
| 746 if (!node) | 727 if (!node) |
| 747 return; // Explicitly allow NULL to be passed in. | 728 return; // Explicitly allow NULL to be passed in. |
| 748 SchedulePaintInRect(GetBoundsForNode(node)); | 729 SchedulePaintInRect(GetBackgroundBoundsForNode(node)); |
| 749 } | 730 } |
| 750 | 731 |
| 751 void TreeView::PaintRows(gfx::Canvas* canvas, | 732 void TreeView::PaintRows(gfx::Canvas* canvas, |
| 752 int min_row, | 733 int min_row, |
| 753 int max_row, | 734 int max_row, |
| 754 InternalNode* node, | 735 InternalNode* node, |
| 755 int depth, | 736 int depth, |
| 756 int* row) { | 737 int* row) { |
| 757 if (*row >= max_row) | 738 if (*row >= max_row) |
| 758 return; | 739 return; |
| 759 | 740 |
| 760 if (*row >= min_row && *row < max_row) | 741 if (*row >= min_row && *row < max_row) |
| 761 PaintRow(canvas, node, *row, depth); | 742 PaintRow(canvas, node, *row, depth); |
| 762 (*row)++; | 743 (*row)++; |
| 763 if (!node->is_expanded()) | 744 if (!node->is_expanded()) |
| 764 return; | 745 return; |
| 765 depth++; | 746 depth++; |
| 766 for (int i = 0; i < node->child_count() && *row < max_row; ++i) | 747 for (int i = 0; i < node->child_count() && *row < max_row; ++i) |
| 767 PaintRows(canvas, min_row, max_row, node->GetChild(i), depth, row); | 748 PaintRows(canvas, min_row, max_row, node->GetChild(i), depth, row); |
| 768 } | 749 } |
| 769 | 750 |
| 770 void TreeView::PaintRow(gfx::Canvas* canvas, | 751 void TreeView::PaintRow(gfx::Canvas* canvas, |
| 771 InternalNode* node, | 752 InternalNode* node, |
| 772 int row, | 753 int row, |
| 773 int depth) { | 754 int depth) { |
| 774 gfx::Rect bounds(GetBoundsForNodeImpl(node, row, depth)); | 755 gfx::Rect bounds(GetForegroundBoundsForNodeImpl(node, row, depth)); |
| 756 const SkColor selected_row_bg_color = GetNativeTheme()->GetSystemColor( |
| 757 text_background_color_id(HasFocus() || editing_)); |
| 758 |
| 759 // Paint the row background. |
| 760 if (PlatformStyle::kTreeViewSelectionPaintsEntireRow && |
| 761 selected_node_ == node) { |
| 762 canvas->FillRect(GetBackgroundBoundsForNode(node), selected_row_bg_color); |
| 763 } |
| 775 | 764 |
| 776 if (model_->GetChildCount(node->model_node())) | 765 if (model_->GetChildCount(node->model_node())) |
| 777 PaintExpandControl(canvas, bounds, node->is_expanded()); | 766 PaintExpandControl(canvas, bounds, node->is_expanded()); |
| 778 | 767 |
| 779 // Paint the icon. | 768 // Paint the icon. |
| 780 gfx::ImageSkia icon; | 769 gfx::ImageSkia icon; |
| 781 int icon_index = model_->GetIconIndex(node->model_node()); | 770 int icon_index = model_->GetIconIndex(node->model_node()); |
| 782 if (icon_index != -1) | 771 if (icon_index != -1) |
| 783 icon = icons_[icon_index]; | 772 icon = icons_[icon_index]; |
| 784 else if (node == selected_node_) | 773 else if (node == selected_node_) |
| 785 icon = open_icon_; | 774 icon = open_icon_; |
| 786 else | 775 else |
| 787 icon = closed_icon_; | 776 icon = closed_icon_; |
| 788 int icon_x = kArrowRegionSize + kImagePadding + | 777 int icon_x = kArrowRegionSize + kImagePadding + |
| 789 (open_icon_.width() - icon.width()) / 2; | 778 (open_icon_.width() - icon.width()) / 2; |
| 790 if (base::i18n::IsRTL()) | 779 if (base::i18n::IsRTL()) |
| 791 icon_x = bounds.right() - icon_x - open_icon_.width(); | 780 icon_x = bounds.right() - icon_x - open_icon_.width(); |
| 792 else | 781 else |
| 793 icon_x += bounds.x(); | 782 icon_x += bounds.x(); |
| 794 canvas->DrawImageInt( | 783 canvas->DrawImageInt( |
| 795 icon, icon_x, | 784 icon, icon_x, |
| 796 bounds.y() + (bounds.height() - icon.height()) / 2); | 785 bounds.y() + (bounds.height() - icon.height()) / 2); |
| 797 | 786 |
| 798 if (!editing_ || node != selected_node_) { | 787 // Paint the text background and text. In edit mode, the selected node is a |
| 799 gfx::Rect text_bounds(bounds.x() + text_offset_, bounds.y(), | 788 // separate editing control, so it does not need to be painted here. |
| 800 bounds.width() - text_offset_, bounds.height()); | 789 if (editing_ && selected_node_ == node) |
| 801 if (base::i18n::IsRTL()) | 790 return; |
| 802 text_bounds.set_x(bounds.x()); | 791 |
| 803 if (node == selected_node_) { | 792 gfx::Rect text_bounds(GetTextBoundsForNode(node)); |
| 804 const SkColor bg_color = GetNativeTheme()->GetSystemColor( | 793 if (base::i18n::IsRTL()) |
| 805 text_background_color_id(HasFocus())); | 794 text_bounds.set_x(bounds.x()); |
| 806 canvas->FillRect(text_bounds, bg_color); | 795 |
| 807 if (HasFocus()) | 796 // Paint the background on the selected row. |
| 808 canvas->DrawFocusRect(text_bounds); | 797 if (!PlatformStyle::kTreeViewSelectionPaintsEntireRow && |
| 809 } | 798 node == selected_node_) { |
| 810 const ui::NativeTheme::ColorId color_id = | 799 canvas->FillRect(text_bounds, selected_row_bg_color); |
| 811 text_color_id(HasFocus(), node == selected_node_); | 800 if (HasFocus()) |
| 812 const gfx::Rect internal_bounds( | 801 canvas->DrawFocusRect(text_bounds); |
| 813 text_bounds.x() + kTextHorizontalPadding, | |
| 814 text_bounds.y() + kTextVerticalPadding, | |
| 815 text_bounds.width() - kTextHorizontalPadding * 2, | |
| 816 text_bounds.height() - kTextVerticalPadding * 2); | |
| 817 canvas->DrawStringRect(node->model_node()->GetTitle(), font_list_, | |
| 818 GetNativeTheme()->GetSystemColor(color_id), | |
| 819 internal_bounds); | |
| 820 } | 802 } |
| 803 |
| 804 // Paint the text. |
| 805 const ui::NativeTheme::ColorId color_id = |
| 806 text_color_id(HasFocus(), node == selected_node_); |
| 807 const gfx::Rect internal_bounds( |
| 808 text_bounds.x() + kTextHorizontalPadding, |
| 809 text_bounds.y() + kTextVerticalPadding, |
| 810 text_bounds.width() - kTextHorizontalPadding * 2, |
| 811 text_bounds.height() - kTextVerticalPadding * 2); |
| 812 canvas->DrawStringRect(node->model_node()->GetTitle(), font_list_, |
| 813 GetNativeTheme()->GetSystemColor(color_id), |
| 814 internal_bounds); |
| 821 } | 815 } |
| 822 | 816 |
| 823 void TreeView::PaintExpandControl(gfx::Canvas* canvas, | 817 void TreeView::PaintExpandControl(gfx::Canvas* canvas, |
| 824 const gfx::Rect& node_bounds, | 818 const gfx::Rect& node_bounds, |
| 825 bool expanded) { | 819 bool expanded) { |
| 826 int center_x; | 820 int center_x; |
| 827 if (base::i18n::IsRTL()) { | 821 if (base::i18n::IsRTL()) { |
| 828 center_x = node_bounds.right() - kArrowRegionSize + | 822 center_x = node_bounds.right() - kArrowRegionSize + |
| 829 (kArrowRegionSize - 4) / 2; | 823 (kArrowRegionSize - 4) / 2; |
| 830 } else { | 824 } else { |
| (...skipping 30 matching lines...) Expand all Loading... |
| 861 return NULL; | 855 return NULL; |
| 862 if (!parent_internal_node->loaded_children()) { | 856 if (!parent_internal_node->loaded_children()) { |
| 863 if (create_type == DONT_CREATE_IF_NOT_LOADED) | 857 if (create_type == DONT_CREATE_IF_NOT_LOADED) |
| 864 return NULL; | 858 return NULL; |
| 865 LoadChildren(parent_internal_node); | 859 LoadChildren(parent_internal_node); |
| 866 } | 860 } |
| 867 return parent_internal_node->GetChild( | 861 return parent_internal_node->GetChild( |
| 868 model_->GetIndexOf(parent_internal_node->model_node(), model_node)); | 862 model_->GetIndexOf(parent_internal_node->model_node(), model_node)); |
| 869 } | 863 } |
| 870 | 864 |
| 871 gfx::Rect TreeView::GetBoundsForNode(InternalNode* node) { | 865 gfx::Rect TreeView::GetBackgroundBoundsForNode(InternalNode* node) { |
| 866 if (!PlatformStyle::kTreeViewSelectionPaintsEntireRow) |
| 867 return GetForegroundBoundsForNode(node); |
| 868 |
| 869 int row, ignored_depth; |
| 870 row = GetRowForInternalNode(node, &ignored_depth); |
| 871 return gfx::Rect(bounds().x(), row * row_height_ + kVerticalInset, |
| 872 bounds().width(), row_height_); |
| 873 } |
| 874 |
| 875 gfx::Rect TreeView::GetForegroundBoundsForNode(InternalNode* node) { |
| 872 int row, depth; | 876 int row, depth; |
| 873 row = GetRowForInternalNode(node, &depth); | 877 row = GetRowForInternalNode(node, &depth); |
| 874 return GetBoundsForNodeImpl(node, row, depth); | 878 return GetForegroundBoundsForNodeImpl(node, row, depth); |
| 875 } | 879 } |
| 876 | 880 |
| 877 gfx::Rect TreeView::GetBoundsForNodeImpl(InternalNode* node, | 881 gfx::Rect TreeView::GetTextBoundsForNode(InternalNode* node) { |
| 878 int row, | 882 gfx::Rect bounds(GetForegroundBoundsForNode(node)); |
| 879 int depth) { | 883 bounds.Inset(text_offset_, 0, 0, 0); |
| 884 return bounds; |
| 885 } |
| 886 |
| 887 gfx::Rect TreeView::GetForegroundBoundsForNodeImpl(InternalNode* node, |
| 888 int row, |
| 889 int depth) { |
| 880 gfx::Rect rect(depth * kIndent + kHorizontalInset, | 890 gfx::Rect rect(depth * kIndent + kHorizontalInset, |
| 881 row * row_height_ + kVerticalInset, | 891 row * row_height_ + kVerticalInset, |
| 882 text_offset_ + node->text_width() + | 892 text_offset_ + node->text_width() + |
| 883 kTextHorizontalPadding * 2, | 893 kTextHorizontalPadding * 2, |
| 884 row_height_); | 894 row_height_); |
| 885 rect.set_x(GetMirroredXWithWidthInView(rect.x(), rect.width())); | 895 rect.set_x(GetMirroredXWithWidthInView(rect.x(), rect.width())); |
| 886 return rect; | 896 return rect; |
| 887 } | 897 } |
| 888 | 898 |
| 889 int TreeView::GetRowForInternalNode(InternalNode* node, int* depth) { | 899 int TreeView::GetRowForInternalNode(InternalNode* node, int* depth) { |
| 890 DCHECK(!node->parent() || IsExpanded(node->parent()->model_node())); | 900 DCHECK(!node->parent() || IsExpanded(node->parent()->model_node())); |
| 891 *depth = -1; | 901 *depth = -1; |
| 892 int row = -1; | 902 int row = -1; |
| 893 InternalNode* tmp_node = node; | 903 InternalNode* tmp_node = node; |
| 894 while (tmp_node->parent()) { | 904 while (tmp_node->parent()) { |
| 895 int index_in_parent = tmp_node->parent()->GetIndexOf(tmp_node); | 905 int index_in_parent = tmp_node->parent()->GetIndexOf(tmp_node); |
| 896 (*depth)++; | 906 (*depth)++; |
| 897 row++; // For node. | 907 row++; // For node. |
| 898 for (int i = 0; i < index_in_parent; ++i) | 908 for (int i = 0; i < index_in_parent; ++i) |
| 899 row += tmp_node->parent()->GetChild(i)->NumExpandedNodes(); | 909 row += tmp_node->parent()->GetChild(i)->NumExpandedNodes(); |
| 900 tmp_node = tmp_node->parent(); | 910 tmp_node = tmp_node->parent(); |
| 901 } | 911 } |
| 902 if (root_shown_) { | 912 if (root_shown_) { |
| 903 (*depth)++; | 913 (*depth)++; |
| 904 row++; | 914 row++; |
| 905 } | 915 } |
| 906 return row; | 916 return row; |
| 907 } | 917 } |
| 908 | 918 |
| 919 TreeView::InternalNode* TreeView::GetNodeAtPoint(const gfx::Point& point) { |
| 920 int row = (point.y() - kVerticalInset) / row_height_; |
| 921 int depth = -1; |
| 922 InternalNode* node = GetNodeByRow(row, &depth); |
| 923 if (!node) |
| 924 return nullptr; |
| 925 |
| 926 // If the entire row gets a selected background, clicking anywhere in the row |
| 927 // serves to hit this node. |
| 928 if (PlatformStyle::kTreeViewSelectionPaintsEntireRow) |
| 929 return node; |
| 930 gfx::Rect bounds(GetForegroundBoundsForNodeImpl(node, row, depth)); |
| 931 return bounds.Contains(point) ? node : nullptr; |
| 932 } |
| 933 |
| 909 TreeView::InternalNode* TreeView::GetNodeByRow(int row, int* depth) { | 934 TreeView::InternalNode* TreeView::GetNodeByRow(int row, int* depth) { |
| 910 int current_row = root_row(); | 935 int current_row = root_row(); |
| 911 *depth = 0; | 936 *depth = 0; |
| 912 return GetNodeByRowImpl(&root_, row, root_depth(), ¤t_row, depth); | 937 return GetNodeByRowImpl(&root_, row, root_depth(), ¤t_row, depth); |
| 913 } | 938 } |
| 914 | 939 |
| 915 TreeView::InternalNode* TreeView::GetNodeByRowImpl(InternalNode* node, | 940 TreeView::InternalNode* TreeView::GetNodeByRowImpl(InternalNode* node, |
| 916 int target_row, | 941 int target_row, |
| 917 int current_depth, | 942 int current_depth, |
| 918 int* current_row, | 943 int* current_row, |
| (...skipping 88 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1007 } | 1032 } |
| 1008 return return_value; | 1033 return return_value; |
| 1009 } | 1034 } |
| 1010 | 1035 |
| 1011 PrefixSelector* TreeView::GetPrefixSelector() { | 1036 PrefixSelector* TreeView::GetPrefixSelector() { |
| 1012 if (!selector_) | 1037 if (!selector_) |
| 1013 selector_.reset(new PrefixSelector(this)); | 1038 selector_.reset(new PrefixSelector(this)); |
| 1014 return selector_.get(); | 1039 return selector_.get(); |
| 1015 } | 1040 } |
| 1016 | 1041 |
| 1042 bool TreeView::IsPointInExpandControl(InternalNode* node, |
| 1043 const gfx::Point& point) { |
| 1044 if (!model_->GetChildCount(node->model_node())) |
| 1045 return false; |
| 1046 |
| 1047 int depth = -1; |
| 1048 int row = GetRowForInternalNode(node, &depth); |
| 1049 |
| 1050 int arrow_dx = depth * kIndent + kHorizontalInset; |
| 1051 gfx::Rect arrow_bounds(bounds().x() + arrow_dx, |
| 1052 row * row_height_ + kVerticalInset, kArrowRegionSize, |
| 1053 row_height_); |
| 1054 if (base::i18n::IsRTL()) |
| 1055 arrow_bounds.set_x(bounds().width() - arrow_dx - kArrowRegionSize); |
| 1056 return arrow_bounds.Contains(point); |
| 1057 } |
| 1058 |
| 1017 // InternalNode ---------------------------------------------------------------- | 1059 // InternalNode ---------------------------------------------------------------- |
| 1018 | 1060 |
| 1019 TreeView::InternalNode::InternalNode() | 1061 TreeView::InternalNode::InternalNode() |
| 1020 : model_node_(NULL), | 1062 : model_node_(NULL), |
| 1021 loaded_children_(false), | 1063 loaded_children_(false), |
| 1022 is_expanded_(false), | 1064 is_expanded_(false), |
| 1023 text_width_(0) { | 1065 text_width_(0) { |
| 1024 } | 1066 } |
| 1025 | 1067 |
| 1026 TreeView::InternalNode::~InternalNode() { | 1068 TreeView::InternalNode::~InternalNode() { |
| (...skipping 20 matching lines...) Expand all Loading... |
| 1047 if (!is_expanded_) | 1089 if (!is_expanded_) |
| 1048 return max_width; | 1090 return max_width; |
| 1049 for (int i = 0; i < child_count(); ++i) { | 1091 for (int i = 0; i < child_count(); ++i) { |
| 1050 max_width = std::max(max_width, | 1092 max_width = std::max(max_width, |
| 1051 GetChild(i)->GetMaxWidth(indent, depth + 1)); | 1093 GetChild(i)->GetMaxWidth(indent, depth + 1)); |
| 1052 } | 1094 } |
| 1053 return max_width; | 1095 return max_width; |
| 1054 } | 1096 } |
| 1055 | 1097 |
| 1056 } // namespace views | 1098 } // namespace views |
| OLD | NEW |