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 "ash/launcher/launcher_view.h" | 5 #include "ash/launcher/launcher_view.h" |
6 | 6 |
7 #include <algorithm> | 7 #include <algorithm> |
8 | 8 |
9 #include "ash/ash_constants.h" | 9 #include "ash/ash_constants.h" |
10 #include "ash/ash_switches.h" | 10 #include "ash/ash_switches.h" |
(...skipping 48 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
59 namespace internal { | 59 namespace internal { |
60 | 60 |
61 // Default amount content is inset on the left edge. | 61 // Default amount content is inset on the left edge. |
62 const int kDefaultLeadingInset = 8; | 62 const int kDefaultLeadingInset = 8; |
63 | 63 |
64 // Minimum distance before drag starts. | 64 // Minimum distance before drag starts. |
65 const int kMinimumDragDistance = 8; | 65 const int kMinimumDragDistance = 8; |
66 | 66 |
67 // Size between the buttons. | 67 // Size between the buttons. |
68 const int kButtonSpacing = 4; | 68 const int kButtonSpacing = 4; |
| 69 const int kAlternateButtonSpacing = 10; |
| 70 |
| 71 // Size allocated to for each button. |
| 72 const int kButtonSize = 44; |
69 | 73 |
70 // Additional spacing for the left and right side of icons. | 74 // Additional spacing for the left and right side of icons. |
71 const int kHorizontalIconSpacing = 2; | 75 const int kHorizontalIconSpacing = 2; |
72 | 76 |
73 // Inset for items which do not have an icon. | 77 // Inset for items which do not have an icon. |
74 const int kHorizontalNoIconInsetSpacing = | 78 const int kHorizontalNoIconInsetSpacing = |
75 kHorizontalIconSpacing + kDefaultLeadingInset; | 79 kHorizontalIconSpacing + kDefaultLeadingInset; |
76 | 80 |
77 // The proportion of the launcher space reserved for non-panel icons. Panels | 81 // The proportion of the launcher space reserved for non-panel icons. Panels |
78 // may flow into this space but will be put into the overflow bubble if there | 82 // may flow into this space but will be put into the overflow bubble if there |
(...skipping 600 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
679 | 683 |
680 void LauncherView::CalculateIdealBounds(IdealBounds* bounds) { | 684 void LauncherView::CalculateIdealBounds(IdealBounds* bounds) { |
681 ShelfLayoutManager* shelf = tooltip_->shelf_layout_manager(); | 685 ShelfLayoutManager* shelf = tooltip_->shelf_layout_manager(); |
682 | 686 |
683 int available_size = shelf->PrimaryAxisValue(width(), height()); | 687 int available_size = shelf->PrimaryAxisValue(width(), height()); |
684 DCHECK(model_->item_count() == view_model_->view_size()); | 688 DCHECK(model_->item_count() == view_model_->view_size()); |
685 if (!available_size) | 689 if (!available_size) |
686 return; | 690 return; |
687 | 691 |
688 int first_panel_index = model_->FirstPanelIndex(); | 692 int first_panel_index = model_->FirstPanelIndex(); |
689 // TODO(harrym): if alternate shelf layout stays, rename app_list_index. | 693 int last_button_index = first_panel_index - 1; |
690 int app_list_index = first_panel_index - 1; | |
691 | 694 |
692 // Initial x,y values account both leading_inset in primary | 695 // Initial x,y values account both leading_inset in primary |
693 // coordinate and secondary coordinate based on the dynamic edge of the | 696 // coordinate and secondary coordinate based on the dynamic edge of the |
694 // launcher (eg top edge on bottom-aligned launcher). | 697 // launcher (eg top edge on bottom-aligned launcher). |
695 int x = shelf->SelectValueForShelfAlignment( | 698 int inset = ash::switches::UseAlternateShelfLayout() ? 0 : leading_inset(); |
696 leading_inset(), | 699 int x = shelf->SelectValueForShelfAlignment(inset, 0, 0, inset); |
697 0, | 700 int y = shelf->SelectValueForShelfAlignment(0, inset, inset, 0); |
698 0, | |
699 leading_inset()); | |
700 int y = shelf->SelectValueForShelfAlignment( | |
701 0, | |
702 leading_inset(), | |
703 leading_inset(), | |
704 0); | |
705 | 701 |
706 int shelf_size = ash::switches::UseAlternateShelfLayout() ? | 702 int button_size = ash::switches::UseAlternateShelfLayout() ? |
707 ShelfLayoutManager::kShelfSize : kLauncherPreferredSize; | 703 kButtonSize : kLauncherPreferredSize; |
| 704 int button_spacing = ash::switches::UseAlternateShelfLayout() ? |
| 705 kAlternateButtonSpacing : kButtonSpacing; |
708 | 706 |
709 int w = shelf->PrimaryAxisValue(shelf_size, width()); | 707 int w = shelf->PrimaryAxisValue(button_size, width()); |
710 int h = shelf->PrimaryAxisValue(height(), shelf_size); | 708 int h = shelf->PrimaryAxisValue(height(), button_size); |
711 for (int i = 0; i < view_model_->view_size(); ++i) { | 709 for (int i = 0; i < view_model_->view_size(); ++i) { |
712 if (i < first_visible_index_) { | 710 if (i < first_visible_index_) { |
713 view_model_->set_ideal_bounds(i, gfx::Rect(x, y, 0, 0)); | 711 view_model_->set_ideal_bounds(i, gfx::Rect(x, y, 0, 0)); |
714 continue; | 712 continue; |
715 } | 713 } |
716 | 714 |
717 view_model_->set_ideal_bounds(i, gfx::Rect(x, y, w, h)); | 715 view_model_->set_ideal_bounds(i, gfx::Rect(x, y, w, h)); |
718 if (i != app_list_index) { | 716 if (i != last_button_index) { |
719 x = shelf->PrimaryAxisValue(x + w + kButtonSpacing, x); | 717 x = shelf->PrimaryAxisValue(x + w + button_spacing, x); |
720 y = shelf->PrimaryAxisValue(y, y + h + kButtonSpacing); | 718 y = shelf->PrimaryAxisValue(y, y + h + button_spacing); |
721 } | 719 } |
722 } | 720 } |
723 | 721 |
724 if (is_overflow_mode()) { | 722 if (is_overflow_mode()) { |
725 DCHECK_LT(last_visible_index_, view_model_->view_size()); | 723 DCHECK_LT(last_visible_index_, view_model_->view_size()); |
726 for (int i = 0; i < view_model_->view_size(); ++i) { | 724 for (int i = 0; i < view_model_->view_size(); ++i) { |
727 view_model_->view_at(i)->SetVisible( | 725 bool visible = i >= first_visible_index_ && |
728 i >= first_visible_index_ && | 726 i <= last_visible_index_; |
729 i != app_list_index && | 727 if (!ash::switches::UseAlternateShelfLayout()) |
730 i <= last_visible_index_); | 728 visible &= i != last_button_index; |
| 729 view_model_->view_at(i)->SetVisible(visible); |
731 } | 730 } |
732 return; | 731 return; |
733 } | 732 } |
734 | 733 |
735 // To address Fitt's law, we make the first launcher button include the | 734 // To address Fitt's law, we make the first launcher button include the |
736 // leading inset (if there is one). | 735 // leading inset (if there is one). |
737 if (view_model_->view_size() > 0) { | 736 if (!ash::switches::UseAlternateShelfLayout()) { |
738 view_model_->set_ideal_bounds(0, gfx::Rect(gfx::Size( | 737 if (view_model_->view_size() > 0) { |
739 shelf->PrimaryAxisValue(leading_inset() + w, w), | 738 view_model_->set_ideal_bounds(0, gfx::Rect(gfx::Size( |
740 shelf->PrimaryAxisValue(h, leading_inset() + h)))); | 739 shelf->PrimaryAxisValue(inset + w, w), |
| 740 shelf->PrimaryAxisValue(h, inset + h)))); |
| 741 } |
741 } | 742 } |
742 | 743 |
743 // Right aligned icons. | 744 // Right aligned icons. |
744 int end_position = available_size - kButtonSpacing; | 745 int end_position = available_size - button_spacing; |
745 x = shelf->PrimaryAxisValue(end_position, 0); | 746 x = shelf->PrimaryAxisValue(end_position, 0); |
746 y = shelf->PrimaryAxisValue(0, end_position); | 747 y = shelf->PrimaryAxisValue(0, end_position); |
747 for (int i = view_model_->view_size() - 1; | 748 for (int i = view_model_->view_size() - 1; |
748 i >= first_panel_index; --i) { | 749 i >= first_panel_index; --i) { |
749 x = shelf->PrimaryAxisValue(x - w - kButtonSpacing, x); | 750 x = shelf->PrimaryAxisValue(x - w - button_spacing, x); |
750 y = shelf->PrimaryAxisValue(y, y - h - kButtonSpacing); | 751 y = shelf->PrimaryAxisValue(y, y - h - button_spacing); |
751 view_model_->set_ideal_bounds(i, gfx::Rect(x, y, w, h)); | 752 view_model_->set_ideal_bounds(i, gfx::Rect(x, y, w, h)); |
752 end_position = shelf->PrimaryAxisValue(x, y); | 753 end_position = shelf->PrimaryAxisValue(x, y); |
753 } | 754 } |
754 | 755 |
755 // Icons on the left / top are guaranteed up to kLeftIconProportion of | 756 // Icons on the left / top are guaranteed up to kLeftIconProportion of |
756 // the available space. | 757 // the available space. |
757 int last_icon_position = shelf->PrimaryAxisValue( | 758 int last_icon_position = shelf->PrimaryAxisValue( |
758 view_model_->ideal_bounds(first_panel_index - 1).right(), | 759 view_model_->ideal_bounds(last_button_index).right(), |
759 view_model_->ideal_bounds(first_panel_index - 1).bottom()) + | 760 view_model_->ideal_bounds(last_button_index).bottom()) |
760 2 * kLauncherPreferredSize + leading_inset(); | 761 + button_size + inset; |
| 762 if (!ash::switches::UseAlternateShelfLayout()) |
| 763 last_icon_position += button_size; |
761 int reserved_icon_space = available_size * kReservedNonPanelIconProportion; | 764 int reserved_icon_space = available_size * kReservedNonPanelIconProportion; |
762 if (last_icon_position < reserved_icon_space) | 765 if (last_icon_position < reserved_icon_space) |
763 end_position = last_icon_position; | 766 end_position = last_icon_position; |
764 else | 767 else |
765 end_position = std::max(end_position, reserved_icon_space); | 768 end_position = std::max(end_position, reserved_icon_space); |
766 | 769 |
767 bounds->overflow_bounds.set_size(gfx::Size( | 770 bounds->overflow_bounds.set_size(gfx::Size( |
768 shelf->PrimaryAxisValue(w, width()), | 771 shelf->PrimaryAxisValue(w, width()), |
769 shelf->PrimaryAxisValue(height(), h))); | 772 shelf->PrimaryAxisValue(height(), h))); |
770 last_visible_index_ = DetermineLastVisibleIndex( | 773 if (ash::switches::UseAlternateShelfLayout()) |
771 end_position - leading_inset() - 2 * kLauncherPreferredSize); | 774 last_visible_index_ = DetermineLastVisibleIndex( |
| 775 end_position - button_size); |
| 776 else |
| 777 last_visible_index_ = DetermineLastVisibleIndex( |
| 778 end_position - inset - 2 * button_size); |
772 last_hidden_index_ = DetermineFirstVisiblePanelIndex(end_position) - 1; | 779 last_hidden_index_ = DetermineFirstVisiblePanelIndex(end_position) - 1; |
773 bool show_overflow = (last_visible_index_ + 1 < app_list_index || | 780 bool show_overflow = |
774 last_hidden_index_ >= first_panel_index); | 781 ((ash::switches::UseAlternateShelfLayout() ? 0 : 1) + |
| 782 last_visible_index_ < last_button_index || |
| 783 last_hidden_index_ >= first_panel_index); |
775 | 784 |
| 785 // Create Space for the overflow button |
| 786 if (show_overflow && ash::switches::UseAlternateShelfLayout()) { |
| 787 DCHECK(last_visible_index_ > 0); |
| 788 --last_visible_index_; |
| 789 } |
776 for (int i = 0; i < view_model_->view_size(); ++i) { | 790 for (int i = 0; i < view_model_->view_size(); ++i) { |
777 view_model_->view_at(i)->SetVisible( | 791 bool visible = i <= last_visible_index_ || i > last_hidden_index_; |
778 i <= last_visible_index_ || | 792 // Always show the app list. |
779 i == app_list_index || | 793 if (!ash::switches::UseAlternateShelfLayout()) |
780 i > last_hidden_index_); | 794 visible |= (i == last_button_index); |
| 795 view_model_->view_at(i)->SetVisible(visible); |
781 } | 796 } |
782 | 797 |
783 overflow_button_->SetVisible(show_overflow); | 798 overflow_button_->SetVisible(show_overflow); |
784 if (show_overflow) { | 799 if (show_overflow) { |
785 DCHECK_NE(0, view_model_->view_size()); | 800 DCHECK_NE(0, view_model_->view_size()); |
786 if (last_visible_index_ == -1) { | 801 if (last_visible_index_ == -1) { |
787 x = shelf->SelectValueForShelfAlignment( | 802 x = shelf->SelectValueForShelfAlignment(inset, 0, 0, inset); |
788 leading_inset(), | 803 y = shelf->SelectValueForShelfAlignment(0, inset, inset, 0); |
789 0, | 804 } else if (last_visible_index_ == last_button_index) { |
790 0, | |
791 leading_inset()); | |
792 y = shelf->SelectValueForShelfAlignment( | |
793 0, | |
794 leading_inset(), | |
795 leading_inset(), | |
796 0); | |
797 } else if (last_visible_index_ == app_list_index) { | |
798 x = view_model_->ideal_bounds(last_visible_index_).x(); | 805 x = view_model_->ideal_bounds(last_visible_index_).x(); |
799 y = view_model_->ideal_bounds(last_visible_index_).y(); | 806 y = view_model_->ideal_bounds(last_visible_index_).y(); |
800 } else { | 807 } else { |
801 x = shelf->PrimaryAxisValue( | 808 x = shelf->PrimaryAxisValue( |
802 view_model_->ideal_bounds(last_visible_index_).right(), | 809 view_model_->ideal_bounds(last_visible_index_).right(), |
803 view_model_->ideal_bounds(last_visible_index_).x()); | 810 view_model_->ideal_bounds(last_visible_index_).x()); |
804 y = shelf->PrimaryAxisValue( | 811 y = shelf->PrimaryAxisValue( |
805 view_model_->ideal_bounds(last_visible_index_).y(), | 812 view_model_->ideal_bounds(last_visible_index_).y(), |
806 view_model_->ideal_bounds(last_visible_index_).bottom()); | 813 view_model_->ideal_bounds(last_visible_index_).bottom()); |
807 } | 814 } |
808 gfx::Rect app_list_bounds = view_model_->ideal_bounds(app_list_index); | |
809 bounds->overflow_bounds.set_x(x); | |
810 bounds->overflow_bounds.set_y(y); | |
811 | |
812 // Set all hidden panel icon positions to be on the overflow button. | 815 // Set all hidden panel icon positions to be on the overflow button. |
813 for (int i = first_panel_index; i <= last_hidden_index_; ++i) | 816 for (int i = first_panel_index; i <= last_hidden_index_; ++i) |
814 view_model_->set_ideal_bounds(i, gfx::Rect(x, y, w, h)); | 817 view_model_->set_ideal_bounds(i, gfx::Rect(x, y, w, h)); |
815 | 818 |
816 x = shelf->PrimaryAxisValue(x + w + kButtonSpacing, x); | 819 bounds->overflow_bounds.set_x(x); |
817 y = shelf->PrimaryAxisValue(y, y + h + kButtonSpacing); | 820 bounds->overflow_bounds.set_y(y); |
818 app_list_bounds.set_x(x); | 821 if (!ash::switches::UseAlternateShelfLayout()) { |
819 app_list_bounds.set_y(y); | 822 // Position app list after overflow button. |
820 view_model_->set_ideal_bounds(app_list_index, app_list_bounds); | 823 gfx::Rect app_list_bounds = view_model_->ideal_bounds(last_button_index); |
821 | 824 |
| 825 x = shelf->PrimaryAxisValue(x + w + button_spacing, x); |
| 826 y = shelf->PrimaryAxisValue(y, y + h + button_spacing); |
| 827 app_list_bounds.set_x(x); |
| 828 app_list_bounds.set_y(y); |
| 829 view_model_->set_ideal_bounds(last_button_index, app_list_bounds); |
| 830 } |
822 if (overflow_bubble_.get() && overflow_bubble_->IsShowing()) | 831 if (overflow_bubble_.get() && overflow_bubble_->IsShowing()) |
823 UpdateOverflowRange(overflow_bubble_->launcher_view()); | 832 UpdateOverflowRange(overflow_bubble_->launcher_view()); |
824 } else { | 833 } else { |
825 if (overflow_bubble_) | 834 if (overflow_bubble_) |
826 overflow_bubble_->Hide(); | 835 overflow_bubble_->Hide(); |
827 } | 836 } |
828 } | 837 } |
829 | 838 |
830 int LauncherView::DetermineLastVisibleIndex(int max_value) const { | 839 int LauncherView::DetermineLastVisibleIndex(int max_value) const { |
831 ShelfLayoutManager* shelf = tooltip_->shelf_layout_manager(); | 840 ShelfLayoutManager* shelf = tooltip_->shelf_layout_manager(); |
(...skipping 197 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1029 return; | 1038 return; |
1030 | 1039 |
1031 // Change the model, the LauncherItemMoved() callback will handle the | 1040 // Change the model, the LauncherItemMoved() callback will handle the |
1032 // |view_model_| update. | 1041 // |view_model_| update. |
1033 model_->Move(current_index, target_index); | 1042 model_->Move(current_index, target_index); |
1034 bounds_animator_->StopAnimatingView(drag_view_); | 1043 bounds_animator_->StopAnimatingView(drag_view_); |
1035 } | 1044 } |
1036 | 1045 |
1037 bool LauncherView::SameDragType(LauncherItemType typea, | 1046 bool LauncherView::SameDragType(LauncherItemType typea, |
1038 LauncherItemType typeb) const { | 1047 LauncherItemType typeb) const { |
1039 if (ash::switches::UseAlternateShelfLayout()) { | 1048 switch (typea) { |
1040 // TODO(harrym): Allow app list to be repositionable, if this goes live | 1049 case TYPE_TABBED: |
1041 // (no flag) the pref file has to be updated so the changes persist. | 1050 case TYPE_PLATFORM_APP: |
1042 switch (typea) { | |
1043 case TYPE_TABBED: | |
1044 case TYPE_PLATFORM_APP: | |
1045 return (typeb == TYPE_TABBED || typeb == TYPE_PLATFORM_APP); | 1051 return (typeb == TYPE_TABBED || typeb == TYPE_PLATFORM_APP); |
1046 case TYPE_APP_SHORTCUT: | 1052 case TYPE_APP_SHORTCUT: |
1047 case TYPE_APP_LIST: | 1053 case TYPE_BROWSER_SHORTCUT: |
1048 case TYPE_BROWSER_SHORTCUT: | 1054 return (typeb == TYPE_APP_SHORTCUT || typeb == TYPE_BROWSER_SHORTCUT); |
1049 return (typeb == TYPE_APP_SHORTCUT || | 1055 case TYPE_WINDOWED_APP: |
1050 typeb == TYPE_APP_LIST || | 1056 case TYPE_APP_LIST: |
1051 typeb == TYPE_BROWSER_SHORTCUT); | 1057 case TYPE_APP_PANEL: |
1052 case TYPE_WINDOWED_APP: | 1058 return typeb == typea; |
1053 case TYPE_APP_PANEL: | |
1054 return typeb == typea; | |
1055 } | |
1056 } else { | |
1057 switch (typea) { | |
1058 case TYPE_TABBED: | |
1059 case TYPE_PLATFORM_APP: | |
1060 return (typeb == TYPE_TABBED || typeb == TYPE_PLATFORM_APP); | |
1061 case TYPE_APP_SHORTCUT: | |
1062 case TYPE_BROWSER_SHORTCUT: | |
1063 return (typeb == TYPE_APP_SHORTCUT || typeb == TYPE_BROWSER_SHORTCUT); | |
1064 case TYPE_WINDOWED_APP: | |
1065 case TYPE_APP_LIST: | |
1066 case TYPE_APP_PANEL: | |
1067 return typeb == typea; | |
1068 } | |
1069 } | 1059 } |
1070 NOTREACHED(); | 1060 NOTREACHED(); |
1071 return false; | 1061 return false; |
1072 } | 1062 } |
1073 | 1063 |
1074 std::pair<int, int> LauncherView::GetDragRange(int index) { | 1064 std::pair<int, int> LauncherView::GetDragRange(int index) { |
1075 int min_index = -1; | 1065 int min_index = -1; |
1076 int max_index = -1; | 1066 int max_index = -1; |
1077 LauncherItemType type = model_->items()[index].type; | 1067 LauncherItemType type = model_->items()[index].type; |
1078 for (int i = 0; i < model_->item_count(); ++i) { | 1068 for (int i = 0; i < model_->item_count(); ++i) { |
(...skipping 25 matching lines...) Expand all Loading... |
1104 overflow_view->Init(); | 1094 overflow_view->Init(); |
1105 overflow_view->OnShelfAlignmentChanged(); | 1095 overflow_view->OnShelfAlignmentChanged(); |
1106 UpdateOverflowRange(overflow_view); | 1096 UpdateOverflowRange(overflow_view); |
1107 | 1097 |
1108 overflow_bubble_->Show(overflow_button_, overflow_view); | 1098 overflow_bubble_->Show(overflow_button_, overflow_view); |
1109 | 1099 |
1110 Shell::GetInstance()->UpdateShelfVisibility(); | 1100 Shell::GetInstance()->UpdateShelfVisibility(); |
1111 } | 1101 } |
1112 | 1102 |
1113 void LauncherView::UpdateFirstButtonPadding() { | 1103 void LauncherView::UpdateFirstButtonPadding() { |
| 1104 if (ash::switches::UseAlternateShelfLayout()) |
| 1105 return; |
| 1106 |
1114 ShelfLayoutManager* shelf = tooltip_->shelf_layout_manager(); | 1107 ShelfLayoutManager* shelf = tooltip_->shelf_layout_manager(); |
1115 | 1108 |
1116 // Creates an empty border for first launcher button to make included leading | 1109 // Creates an empty border for first launcher button to make included leading |
1117 // inset act as the button's padding. This is only needed on button creation | 1110 // inset act as the button's padding. This is only needed on button creation |
1118 // and when shelf alignment changes. | 1111 // and when shelf alignment changes. |
1119 if (view_model_->view_size() > 0) { | 1112 if (view_model_->view_size() > 0) { |
1120 view_model_->view_at(0)->set_border(views::Border::CreateEmptyBorder( | 1113 view_model_->view_at(0)->set_border(views::Border::CreateEmptyBorder( |
1121 shelf->PrimaryAxisValue(0, leading_inset()), | 1114 shelf->PrimaryAxisValue(0, leading_inset()), |
1122 shelf->PrimaryAxisValue(leading_inset(), 0), | 1115 shelf->PrimaryAxisValue(leading_inset(), 0), |
1123 0, | 1116 0, |
(...skipping 582 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1706 bool LauncherView::ShouldShowTooltipForView(const views::View* view) const { | 1699 bool LauncherView::ShouldShowTooltipForView(const views::View* view) const { |
1707 if (view == GetAppListButtonView() && | 1700 if (view == GetAppListButtonView() && |
1708 Shell::GetInstance()->GetAppListWindow()) | 1701 Shell::GetInstance()->GetAppListWindow()) |
1709 return false; | 1702 return false; |
1710 const LauncherItem* item = LauncherItemForView(view); | 1703 const LauncherItem* item = LauncherItemForView(view); |
1711 return (!item || delegate_->ShouldShowTooltip(*item)); | 1704 return (!item || delegate_->ShouldShowTooltip(*item)); |
1712 } | 1705 } |
1713 | 1706 |
1714 } // namespace internal | 1707 } // namespace internal |
1715 } // namespace ash | 1708 } // namespace ash |
OLD | NEW |