diff --git a/FeatureAreas.props b/FeatureAreas.props old mode 100644 new mode 100755 index 87d2acb705..e0e151b676 --- a/FeatureAreas.props +++ b/FeatureAreas.props @@ -210,6 +210,10 @@ + + + productOnly + @@ -271,6 +275,7 @@ true true true + true true diff --git a/MUXControls.sln b/MUXControls.sln old mode 100644 new mode 100755 index e5226c5942..7e2c3740d4 --- a/MUXControls.sln +++ b/MUXControls.sln @@ -681,6 +681,16 @@ Project("{D954291E-2A0B-460D-934E-DC6B0785DB48}") = "InfoBar_TestUI", "dev\InfoB EndProject Project("{D954291E-2A0B-460D-934E-DC6B0785DB48}") = "InfoBar_InteractionTests", "dev\InfoBar\InteractionTests\InfoBar_InteractionTests.shproj", "{F470A64E-780E-45AA-ABB7-73A8734E51D7}" EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "PipsPager", "PipsPager", "{CE0523BB-5799-4BA0-A461-0ABC6E19F969}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "PipsPager", "dev\PipsPager\PipsPager.vcxitems", "{D1EB61D8-C689-4AD1-BD61-FDAA50362563}" +EndProject +Project("{D954291E-2A0B-460D-934E-DC6B0785DB48}") = "PipsPager_APITests", "dev\PipsPager\APITests\PipsPager_APITests.shproj", "{9CF0D73A-E435-4C17-A41C-11E9FA3EEA2F}" +EndProject +Project("{D954291E-2A0B-460D-934E-DC6B0785DB48}") = "PipsPager_TestUI", "dev\PipsPager\TestUI\PipsPager_TestUI.shproj", "{44F0E6BC-6222-4F16-8050-BB31DD804C4A}" +EndProject +Project("{D954291E-2A0B-460D-934E-DC6B0785DB48}") = "PipsPager_InteractionTests", "dev\PipsPager\InteractionTests\PipsPager_InteractionTests.shproj", "{B1D8E6A2-3FE6-4D80-9685-26DF2C9F4331}" +EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "ImageIcon", "ImageIcon", "{BB791907-485F-4A16-9612-7FE07FCD1D21}" EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "ImageIcon", "dev\ImageIcon\ImageIcon.vcxitems", "{9FB38577-696E-47BA-8AE2-F48A3C84A7CA}" @@ -750,6 +760,7 @@ Global dev\TeachingTip\TestUI\TeachingTip_TestUI.projitems*{42a51d3e-f06a-41a0-be4c-f94cddb80678}*SharedItemsImports = 13 dev\RadioButtons\InteractionTests\RadioButtons_InteractionTests.projitems*{42d6e8f9-59fe-4ca5-83eb-69a7622f5742}*SharedItemsImports = 13 dev\TwoPaneView\APITests\TwoPaneView_APITests.projitems*{44deafbc-bb7a-4b02-aeab-29df2c2f8587}*SharedItemsImports = 13 + dev\PipsPager\TestUI\PipsPager_TestUI.projitems*{44f0e6bc-6222-4f16-8050-bb31dd804c4a}*SharedItemsImports = 13 dev\ResourceHelper\ResourceHelper.vcxitems*{45d41acc-2c3c-43d2-bc10-02aa73ffc7c7}*SharedItemsImports = 9 dev\ScrollPresenter\APITests\ScrollPresenter_APITests.projitems*{474b92f7-cd58-fed9-8569-9640529d1871}*SharedItemsImports = 13 dev\NavigationView\NavigationView_InteractionTests\NavigationView_InteractionTests.projitems*{475c3a33-637a-44dc-b789-6c2d78a75283}*SharedItemsImports = 13 @@ -808,6 +819,7 @@ Global dev\Repeater\InteractionTests\Repeater_InteractionTests.projitems*{999e00c9-0e58-402a-8e0e-cbafb0adc7e3}*SharedItemsImports = 13 dev\SwipeControl\SwipeControl_InteractionTests\SwipeControl_InteractionTests.projitems*{9a8da438-193c-4950-a046-2952de2d3b0b}*SharedItemsImports = 13 dev\TwoPaneView\TestUI\TwoPaneView_TestUI.projitems*{9c533ec3-f8fa-4b0e-ba1b-3323932cdfcb}*SharedItemsImports = 13 + dev\PipsPager\APITests\PipsPager_APITests.projitems*{9cf0d73a-e435-4c17-a41c-11e9fa3eea2f}*SharedItemsImports = 13 dev\NumberBox\NumberBox.vcxitems*{9d23c997-1f46-444a-8c07-4a4bff7e4e63}*SharedItemsImports = 9 dev\ImageIcon\ImageIcon.vcxitems*{9fb38577-696e-47ba-8ae2-f48a3c84a7ca}*SharedItemsImports = 9 dev\Repeater\Repeater.vcxitems*{a0aa8919-2140-42db-beb1-b2c3ace594f4}*SharedItemsImports = 9 @@ -850,6 +862,7 @@ Global dev\PagerControl\PagerControl.vcxitems*{ad0c90b0-4845-4d4b-88f1-86f653f8171b}*SharedItemsImports = 4 dev\ParallaxView\ParallaxView.vcxitems*{ad0c90b0-4845-4d4b-88f1-86f653f8171b}*SharedItemsImports = 4 dev\PersonPicture\PersonPicture.vcxitems*{ad0c90b0-4845-4d4b-88f1-86f653f8171b}*SharedItemsImports = 4 + dev\PipsPager\PipsPager.vcxitems*{ad0c90b0-4845-4d4b-88f1-86f653f8171b}*SharedItemsImports = 4 dev\Pivot\Pivot.vcxitems*{ad0c90b0-4845-4d4b-88f1-86f653f8171b}*SharedItemsImports = 4 dev\ProgressBar\ProgressBar.vcxitems*{ad0c90b0-4845-4d4b-88f1-86f653f8171b}*SharedItemsImports = 4 dev\ProgressRing\ProgressRing.vcxitems*{ad0c90b0-4845-4d4b-88f1-86f653f8171b}*SharedItemsImports = 4 @@ -884,6 +897,7 @@ Global dev\TimePicker\TimePicker.vcxitems*{afd20f66-d203-4da9-b8ea-4e3f99a53f99}*SharedItemsImports = 9 dev\CalendarView\CalendarView.vcxitems*{b0016539-9ee1-42b4-a247-fd45c8511656}*SharedItemsImports = 9 dev\PersonPicture\InteractionTests\PersonPicture_InteractionTests.projitems*{b0c15318-1f57-4914-b860-ebf248841511}*SharedItemsImports = 13 + dev\PipsPager\InteractionTests\PipsPager_InteractionTests.projitems*{b1d8e6a2-3fe6-4d80-9685-26df2c9f4331}*SharedItemsImports = 13 dev\TreeView\TestUI\TreeView_TestUI.projitems*{b2c714dd-9c6b-400c-9cef-13a2d48378bd}*SharedItemsImports = 13 dev\AnimatedVisualPlayer\AnimatedVisualPlayer.vcxitems*{b39300d2-4510-44ea-aa7b-eda9118f830e}*SharedItemsImports = 9 dev\ProgressRing\TestUI\ProgressRing_TestUI.projitems*{b58ec806-9951-4e5e-af29-a700a088770e}*SharedItemsImports = 13 @@ -908,6 +922,7 @@ Global dev\LayoutPanel\APITests\LayoutPanel_APITests.projitems*{cddf46ef-aa2d-4bb3-b33e-98b3dbb3c41b}*SharedItemsImports = 13 dev\Interactions\SliderInteraction\SliderInteraction.vcxitems*{d097a4d5-6b61-424d-99f0-f335eff41665}*SharedItemsImports = 9 dev\TabView\InteractionTests\TabView_InteractionTests.projitems*{d1e297b4-5e5b-4807-8624-4141c817a98a}*SharedItemsImports = 13 + dev\PipsPager\PipsPager.vcxitems*{d1eb61d8-c689-4ad1-bd61-fdaa50362563}*SharedItemsImports = 9 dev\MenuFlyout\MenuFlyout.vcxitems*{d5c2b2a0-50af-4ace-939d-17d1ed79fd6f}*SharedItemsImports = 9 dev\Expander\InteractionTests\Expander_InteractionTests.projitems*{d6df4ab9-facc-4e51-8c57-6b1f96919365}*SharedItemsImports = 13 dev\IconSource\APITests\IconSource_APITests.projitems*{d73627e9-564c-4a72-a12d-f6c82f17ad0d}*SharedItemsImports = 13 @@ -962,6 +977,8 @@ Global dev\ParallaxView\TestUI\ParallaxView_TestUI.projitems*{dedc1e4f-cfa5-4443-83eb-e79d425df7e7}*SharedItemsImports = 4 dev\PersonPicture\APITests\PersonPicture_APITests.projitems*{dedc1e4f-cfa5-4443-83eb-e79d425df7e7}*SharedItemsImports = 4 dev\PersonPicture\TestUI\PersonPicture_TestUI.projitems*{dedc1e4f-cfa5-4443-83eb-e79d425df7e7}*SharedItemsImports = 4 + dev\PipsPager\APITests\PipsPager_APITests.projitems*{dedc1e4f-cfa5-4443-83eb-e79d425df7e7}*SharedItemsImports = 4 + dev\PipsPager\TestUI\PipsPager_TestUI.projitems*{dedc1e4f-cfa5-4443-83eb-e79d425df7e7}*SharedItemsImports = 4 dev\Pivot\TestUI\Pivot_TestUI.projitems*{dedc1e4f-cfa5-4443-83eb-e79d425df7e7}*SharedItemsImports = 4 dev\ProgressBar\TestUI\ProgressBar_TestUI.projitems*{dedc1e4f-cfa5-4443-83eb-e79d425df7e7}*SharedItemsImports = 4 dev\ProgressRing\TestUI\ProgressRing_TestUI.projitems*{dedc1e4f-cfa5-4443-83eb-e79d425df7e7}*SharedItemsImports = 4 @@ -1062,6 +1079,8 @@ Global dev\ParallaxView\TestUI\ParallaxView_TestUI.projitems*{fbc396f5-26dd-4ca3-981e-c7bc9fea4546}*SharedItemsImports = 4 dev\PersonPicture\APITests\PersonPicture_APITests.projitems*{fbc396f5-26dd-4ca3-981e-c7bc9fea4546}*SharedItemsImports = 4 dev\PersonPicture\TestUI\PersonPicture_TestUI.projitems*{fbc396f5-26dd-4ca3-981e-c7bc9fea4546}*SharedItemsImports = 4 + dev\PipsPager\APITests\PipsPager_APITests.projitems*{fbc396f5-26dd-4ca3-981e-c7bc9fea4546}*SharedItemsImports = 4 + dev\PipsPager\TestUI\PipsPager_TestUI.projitems*{fbc396f5-26dd-4ca3-981e-c7bc9fea4546}*SharedItemsImports = 4 dev\Pivot\TestUI\Pivot_TestUI.projitems*{fbc396f5-26dd-4ca3-981e-c7bc9fea4546}*SharedItemsImports = 4 dev\ProgressBar\TestUI\ProgressBar_TestUI.projitems*{fbc396f5-26dd-4ca3-981e-c7bc9fea4546}*SharedItemsImports = 4 dev\ProgressRing\TestUI\ProgressRing_TestUI.projitems*{fbc396f5-26dd-4ca3-981e-c7bc9fea4546}*SharedItemsImports = 4 @@ -1733,6 +1752,11 @@ Global {CCC102B7-F5EF-479D-94F1-008D189448B1} = {CEFD707F-6686-4CF4-8D4C-B5FECD50D739} {32DFAF1E-C2EC-4C52-A4D8-B3A3946242B4} = {CEFD707F-6686-4CF4-8D4C-B5FECD50D739} {F470A64E-780E-45AA-ABB7-73A8734E51D7} = {CEFD707F-6686-4CF4-8D4C-B5FECD50D739} + {CE0523BB-5799-4BA0-A461-0ABC6E19F969} = {67599AD5-51EC-44CB-85CE-B60CD8CBA270} + {D1EB61D8-C689-4AD1-BD61-FDAA50362563} = {CE0523BB-5799-4BA0-A461-0ABC6E19F969} + {9CF0D73A-E435-4C17-A41C-11E9FA3EEA2F} = {CE0523BB-5799-4BA0-A461-0ABC6E19F969} + {44F0E6BC-6222-4F16-8050-BB31DD804C4A} = {CE0523BB-5799-4BA0-A461-0ABC6E19F969} + {B1D8E6A2-3FE6-4D80-9685-26DF2C9F4331} = {CE0523BB-5799-4BA0-A461-0ABC6E19F969} {BB791907-485F-4A16-9612-7FE07FCD1D21} = {67599AD5-51EC-44CB-85CE-B60CD8CBA270} {9FB38577-696E-47BA-8AE2-F48A3C84A7CA} = {BB791907-485F-4A16-9612-7FE07FCD1D21} {27AAE2E5-9687-4120-822F-CDB68B9A65B7} = {BB791907-485F-4A16-9612-7FE07FCD1D21} diff --git a/MUXControlsInnerLoop.sln b/MUXControlsInnerLoop.sln old mode 100644 new mode 100755 index 225d5ff516..3ffd728833 --- a/MUXControlsInnerLoop.sln +++ b/MUXControlsInnerLoop.sln @@ -496,6 +496,16 @@ Project("{D954291E-2A0B-460D-934E-DC6B0785DB48}") = "InfoBar_InteractionTests", EndProject Project("{D954291E-2A0B-460D-934E-DC6B0785DB48}") = "InfoBar_TestUI", "dev\InfoBar\TestUI\InfoBar_TestUI.shproj", "{32DFAF1E-C2EC-4C52-A4D8-B3A3946242B4}" EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "PipsPager", "PipsPager", "{AA960C72-877F-4F3C-92D2-7ADD34D643F4}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "PipsPager", "dev\PipsPager\PipsPager.vcxitems", "{D1EB61D8-C689-4AD1-BD61-FDAA50362563}" +EndProject +Project("{D954291E-2A0B-460D-934E-DC6B0785DB48}") = "PipsPager_APITests", "dev\PipsPager\APITests\PipsPager_APITests.shproj", "{9CF0D73A-E435-4C17-A41C-11E9FA3EEA2F}" +EndProject +Project("{D954291E-2A0B-460D-934E-DC6B0785DB48}") = "PipsPager_TestUI", "dev\PipsPager\TestUI\PipsPager_TestUI.shproj", "{44F0E6BC-6222-4F16-8050-BB31DD804C4A}" +EndProject +Project("{D954291E-2A0B-460D-934E-DC6B0785DB48}") = "PipsPager_InteractionTests", "dev\PipsPager\InteractionTests\PipsPager_InteractionTests.shproj", "{B1D8E6A2-3FE6-4D80-9685-26DF2C9F4331}" +EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "ImageIcon", "ImageIcon", "{21638B33-D4DE-4D10-84F8-3E2DACF975C7}" EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "ImageIcon", "dev\ImageIcon\ImageIcon.vcxitems", "{9FB38577-696E-47BA-8AE2-F48A3C84A7CA}" @@ -562,6 +572,7 @@ Global dev\TeachingTip\TestUI\TeachingTip_TestUI.projitems*{42a51d3e-f06a-41a0-be4c-f94cddb80678}*SharedItemsImports = 13 dev\RadioButtons\InteractionTests\RadioButtons_InteractionTests.projitems*{42d6e8f9-59fe-4ca5-83eb-69a7622f5742}*SharedItemsImports = 13 dev\TwoPaneView\APITests\TwoPaneView_APITests.projitems*{44deafbc-bb7a-4b02-aeab-29df2c2f8587}*SharedItemsImports = 13 + dev\PipsPager\TestUI\PipsPager_TestUI.projitems*{44f0e6bc-6222-4f16-8050-bb31dd804c4a}*SharedItemsImports = 13 dev\ResourceHelper\ResourceHelper.vcxitems*{45d41acc-2c3c-43d2-bc10-02aa73ffc7c7}*SharedItemsImports = 9 dev\ScrollPresenter\APITests\ScrollPresenter_APITests.projitems*{474b92f7-cd58-fed9-8569-9640529d1871}*SharedItemsImports = 13 dev\NavigationView\NavigationView_InteractionTests\NavigationView_InteractionTests.projitems*{475c3a33-637a-44dc-b789-6c2d78a75283}*SharedItemsImports = 13 @@ -617,6 +628,7 @@ Global dev\Repeater\InteractionTests\Repeater_InteractionTests.projitems*{999e00c9-0e58-402a-8e0e-cbafb0adc7e3}*SharedItemsImports = 13 dev\SwipeControl\SwipeControl_InteractionTests\SwipeControl_InteractionTests.projitems*{9a8da438-193c-4950-a046-2952de2d3b0b}*SharedItemsImports = 13 dev\TwoPaneView\TestUI\TwoPaneView_TestUI.projitems*{9c533ec3-f8fa-4b0e-ba1b-3323932cdfcb}*SharedItemsImports = 13 + dev\PipsPager\APITests\PipsPager_APITests.projitems*{9cf0d73a-e435-4c17-a41c-11e9fa3eea2f}*SharedItemsImports = 13 dev\NumberBox\NumberBox.vcxitems*{9d23c997-1f46-444a-8c07-4a4bff7e4e63}*SharedItemsImports = 9 dev\ImageIcon\ImageIcon.vcxitems*{9fb38577-696e-47ba-8ae2-f48a3c84a7ca}*SharedItemsImports = 9 dev\Repeater\Repeater.vcxitems*{a0aa8919-2140-42db-beb1-b2c3ace594f4}*SharedItemsImports = 9 @@ -626,6 +638,7 @@ Global dev\Materials\Acrylic\TestUI\AcrylicBrush_TestUI.projitems*{a800e818-7212-4fd7-ae3a-1dcab539db87}*SharedItemsImports = 13 dev\PagerControl\PagerControl.vcxitems*{ab3261a7-9a8d-4a27-aea2-3aac0419c889}*SharedItemsImports = 9 dev\Collections\Collections.vcxitems*{ad0c90b0-4845-4d4b-88f1-86f653f8171b}*SharedItemsImports = 4 + dev\ComboBox\ComboBox.vcxitems*{ad0c90b0-4845-4d4b-88f1-86f653f8171b}*SharedItemsImports = 4 dev\CommonStyles\CommonStyles.vcxitems*{ad0c90b0-4845-4d4b-88f1-86f653f8171b}*SharedItemsImports = 4 dev\Common\Common.vcxitems*{ad0c90b0-4845-4d4b-88f1-86f653f8171b}*SharedItemsImports = 4 dev\DropDownButton\DropDownButton.vcxitems*{ad0c90b0-4845-4d4b-88f1-86f653f8171b}*SharedItemsImports = 4 @@ -634,6 +647,10 @@ Global dev\Lights\Lights.vcxitems*{ad0c90b0-4845-4d4b-88f1-86f653f8171b}*SharedItemsImports = 4 dev\Materials\Acrylic\AcrylicBrush.vcxitems*{ad0c90b0-4845-4d4b-88f1-86f653f8171b}*SharedItemsImports = 4 dev\Materials\Reveal\RevealBrush.vcxitems*{ad0c90b0-4845-4d4b-88f1-86f653f8171b}*SharedItemsImports = 4 + dev\NumberBox\NumberBox.vcxitems*{ad0c90b0-4845-4d4b-88f1-86f653f8171b}*SharedItemsImports = 4 + dev\PagerControl\PagerControl.vcxitems*{ad0c90b0-4845-4d4b-88f1-86f653f8171b}*SharedItemsImports = 4 + dev\PipsPager\PipsPager.vcxitems*{ad0c90b0-4845-4d4b-88f1-86f653f8171b}*SharedItemsImports = 4 + dev\Repeater\Repeater.vcxitems*{ad0c90b0-4845-4d4b-88f1-86f653f8171b}*SharedItemsImports = 4 dev\ResourceHelper\ResourceHelper.vcxitems*{ad0c90b0-4845-4d4b-88f1-86f653f8171b}*SharedItemsImports = 4 dev\SplitButton\SplitButton.vcxitems*{ad0c90b0-4845-4d4b-88f1-86f653f8171b}*SharedItemsImports = 4 dev\Telemetry\Telemetry.vcxitems*{ad0c90b0-4845-4d4b-88f1-86f653f8171b}*SharedItemsImports = 4 @@ -643,6 +660,7 @@ Global dev\RatingControl\InteractionTests\RatingControl_InteractionTests.projitems*{afaad014-132c-4d2a-a28e-4ef717d3e647}*SharedItemsImports = 13 dev\TimePicker\TimePicker.vcxitems*{afd20f66-d203-4da9-b8ea-4e3f99a53f99}*SharedItemsImports = 9 dev\PersonPicture\InteractionTests\PersonPicture_InteractionTests.projitems*{b0c15318-1f57-4914-b860-ebf248841511}*SharedItemsImports = 13 + dev\PipsPager\InteractionTests\PipsPager_InteractionTests.projitems*{b1d8e6a2-3fe6-4d80-9685-26df2c9f4331}*SharedItemsImports = 13 dev\TreeView\TestUI\TreeView_TestUI.projitems*{b2c714dd-9c6b-400c-9cef-13a2d48378bd}*SharedItemsImports = 13 dev\AnimatedVisualPlayer\AnimatedVisualPlayer.vcxitems*{b39300d2-4510-44ea-aa7b-eda9118f830e}*SharedItemsImports = 9 dev\ProgressRing\TestUI\ProgressRing_TestUI.projitems*{b58ec806-9951-4e5e-af29-a700a088770e}*SharedItemsImports = 13 @@ -666,6 +684,7 @@ Global dev\LayoutPanel\APITests\LayoutPanel_APITests.projitems*{cddf46ef-aa2d-4bb3-b33e-98b3dbb3c41b}*SharedItemsImports = 13 dev\Interactions\SliderInteraction\SliderInteraction.vcxitems*{d097a4d5-6b61-424d-99f0-f335eff41665}*SharedItemsImports = 9 dev\TabView\InteractionTests\TabView_InteractionTests.projitems*{d1e297b4-5e5b-4807-8624-4141c817a98a}*SharedItemsImports = 13 + dev\PipsPager\PipsPager.vcxitems*{d1eb61d8-c689-4ad1-bd61-fdaa50362563}*SharedItemsImports = 9 dev\MenuFlyout\MenuFlyout.vcxitems*{d5c2b2a0-50af-4ace-939d-17d1ed79fd6f}*SharedItemsImports = 9 dev\Expander\InteractionTests\Expander_InteractionTests.projitems*{d6df4ab9-facc-4e51-8c57-6b1f96919365}*SharedItemsImports = 13 dev\IconSource\APITests\IconSource_APITests.projitems*{d73627e9-564c-4a72-a12d-f6c82f17ad0d}*SharedItemsImports = 13 @@ -676,6 +695,10 @@ Global dev\TreeView\APITests\TreeView_APITests.projitems*{de885c66-929c-464e-bac4-3e076ec46483}*SharedItemsImports = 13 dev\Pivot\TestUI\Pivot_TestUI.projitems*{deb3fa60-e4a7-4735-89f2-363c7c56b428}*SharedItemsImports = 13 dev\CommonManaged\CommonManaged.projitems*{dedc1e4f-cfa5-4443-83eb-e79d425df7e7}*SharedItemsImports = 4 + dev\PagerControl\APITests\PagerControl_APITests.projitems*{dedc1e4f-cfa5-4443-83eb-e79d425df7e7}*SharedItemsImports = 4 + dev\PagerControl\TestUI\PagerControl_TestUI.projitems*{dedc1e4f-cfa5-4443-83eb-e79d425df7e7}*SharedItemsImports = 4 + dev\PipsPager\APITests\PipsPager_APITests.projitems*{dedc1e4f-cfa5-4443-83eb-e79d425df7e7}*SharedItemsImports = 4 + dev\PipsPager\TestUI\PipsPager_TestUI.projitems*{dedc1e4f-cfa5-4443-83eb-e79d425df7e7}*SharedItemsImports = 4 test\TestAppUtils\TestAppUtils.projitems*{dedc1e4f-cfa5-4443-83eb-e79d425df7e7}*SharedItemsImports = 4 dev\SplitButton\InteractionTests\SplitButton_InteractionTests.projitems*{e1c861e2-c4d9-41e1-aed7-5e203451bd4d}*SharedItemsImports = 13 dev\DatePicker\TestUI\DatePicker_TestUI.projitems*{e20f725c-3a53-463b-ada9-ff2088aaca4d}*SharedItemsImports = 13 @@ -694,6 +717,10 @@ Global dev\Materials\Acrylic\InteractionTests\AcrylicBrush_InteractionTests.projitems*{f601284a-00c1-49f9-99b3-70d45585f784}*SharedItemsImports = 13 dev\SplitButton\SplitButton.vcxitems*{faf114dd-af1f-4d9f-a511-354c19912aad}*SharedItemsImports = 9 dev\CommonManaged\CommonManaged.projitems*{fbc396f5-26dd-4ca3-981e-c7bc9fea4546}*SharedItemsImports = 4 + dev\PagerControl\APITests\PagerControl_APITests.projitems*{fbc396f5-26dd-4ca3-981e-c7bc9fea4546}*SharedItemsImports = 4 + dev\PagerControl\TestUI\PagerControl_TestUI.projitems*{fbc396f5-26dd-4ca3-981e-c7bc9fea4546}*SharedItemsImports = 4 + dev\PipsPager\APITests\PipsPager_APITests.projitems*{fbc396f5-26dd-4ca3-981e-c7bc9fea4546}*SharedItemsImports = 4 + dev\PipsPager\TestUI\PipsPager_TestUI.projitems*{fbc396f5-26dd-4ca3-981e-c7bc9fea4546}*SharedItemsImports = 4 test\TestAppUtils\TestAppUtils.projitems*{fbc396f5-26dd-4ca3-981e-c7bc9fea4546}*SharedItemsImports = 4 dev\Slider\Slider.vcxitems*{fc2178ca-7f72-40f0-916c-a2b3750bbb6c}*SharedItemsImports = 9 dev\LayoutPanel\LayoutPanel.vcxitems*{fd3c1a00-0d07-4849-a3b9-646f0ff21d7b}*SharedItemsImports = 9 @@ -1154,6 +1181,11 @@ Global {CCC102B7-F5EF-479D-94F1-008D189448B1} = {1AD0CB4F-47F0-432B-8D4F-CE33FA3EB8A9} {F470A64E-780E-45AA-ABB7-73A8734E51D7} = {1AD0CB4F-47F0-432B-8D4F-CE33FA3EB8A9} {32DFAF1E-C2EC-4C52-A4D8-B3A3946242B4} = {1AD0CB4F-47F0-432B-8D4F-CE33FA3EB8A9} + {AA960C72-877F-4F3C-92D2-7ADD34D643F4} = {67599AD5-51EC-44CB-85CE-B60CD8CBA270} + {D1EB61D8-C689-4AD1-BD61-FDAA50362563} = {AA960C72-877F-4F3C-92D2-7ADD34D643F4} + {9CF0D73A-E435-4C17-A41C-11E9FA3EEA2F} = {AA960C72-877F-4F3C-92D2-7ADD34D643F4} + {44F0E6BC-6222-4F16-8050-BB31DD804C4A} = {AA960C72-877F-4F3C-92D2-7ADD34D643F4} + {B1D8E6A2-3FE6-4D80-9685-26DF2C9F4331} = {AA960C72-877F-4F3C-92D2-7ADD34D643F4} {21638B33-D4DE-4D10-84F8-3E2DACF975C7} = {67599AD5-51EC-44CB-85CE-B60CD8CBA270} {9FB38577-696E-47BA-8AE2-F48A3C84A7CA} = {21638B33-D4DE-4D10-84F8-3E2DACF975C7} {27AAE2E5-9687-4120-822F-CDB68B9A65B7} = {21638B33-D4DE-4D10-84F8-3E2DACF975C7} diff --git a/build/Localization/Settings/LocConfig.xml b/build/Localization/Settings/LocConfig.xml index 40da925f22..c677ba2a16 100644 --- a/build/Localization/Settings/LocConfig.xml +++ b/build/Localization/Settings/LocConfig.xml @@ -45,5 +45,8 @@ + diff --git a/dev/PipsPager/APITests/PipsPagerTests.cs b/dev/PipsPager/APITests/PipsPagerTests.cs new file mode 100755 index 0000000000..b00280d093 --- /dev/null +++ b/dev/PipsPager/APITests/PipsPagerTests.cs @@ -0,0 +1,136 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. See LICENSE in the project root for license information. + +using Common; +using Microsoft.UI.Xaml.Controls; +using MUXControlsTestApp.Utilities; +using Microsoft.UI.Xaml.Automation.Peers; +using Windows.UI.Xaml.Automation.Provider; +using Windows.UI.Xaml.Automation.Peers; +using Windows.UI.Xaml.Media; +using Windows.UI.Xaml.Controls; +using Windows.UI.Xaml.Automation; +#if USING_TAEF +using WEX.TestExecution; +using WEX.TestExecution.Markup; +using WEX.Logging.Interop; +#else +using Microsoft.VisualStudio.TestTools.UnitTesting; +using Microsoft.VisualStudio.TestTools.UnitTesting.Logging; +#endif + +namespace Windows.UI.Xaml.Tests.MUXControls.ApiTests +{ + [TestClass] + public class PipsPagerTests : ApiTestBase + { + [TestMethod] + public void VerifyAutomationPeerBehavior() + { + RunOnUIThread.Execute(() => + { + var pipsControl = new PipsPager(); + pipsControl.NumberOfPages = 5; + Content = pipsControl; + + var peer = PipsPagerAutomationPeer.CreatePeerForElement(pipsControl); + var selectionPeer = peer as ISelectionProvider; + Verify.AreEqual(false, selectionPeer.CanSelectMultiple); + Verify.AreEqual(true, selectionPeer.IsSelectionRequired); + Verify.AreEqual(AutomationLandmarkType.Navigation, peer.GetLandmarkType()); + }); + } + + [TestMethod] + public void VerifyPipsPagerButtonUIABehavior() + { + RunOnUIThread.Execute(() => + { + var pipsPager = new PipsPager(); + pipsPager.NumberOfPages = 5; + Content = pipsPager; + }); + + IdleSynchronizer.Wait(); + + RunOnUIThread.Execute(() => + { + var rootPanel = VisualTreeHelper.GetChild(Content, 0) as StackPanel; + var repeaterRootParent = VisualTreeHelper.GetChild(rootPanel, 1); + ItemsRepeater repeater = null; + while (repeater == null) + { + var nextChild = VisualTreeHelper.GetChild(repeaterRootParent, 0); + repeater = nextChild as ItemsRepeater; + repeaterRootParent = nextChild; + } + for (int i = 0; i < 5; i++) + { + var button = repeater.TryGetElement(i); + Verify.IsNotNull(button); + Verify.AreEqual(i + 1, button.GetValue(AutomationProperties.PositionInSetProperty)); + Verify.AreEqual(5, button.GetValue(AutomationProperties.SizeOfSetProperty)); + } + }); + } + + [TestMethod] + public void VerifyEmptyPagerDoesNotCrash() + { + RunOnUIThread.Execute(() => + { + Content = new PipsPager(); + }); + + IdleSynchronizer.Wait(); + + RunOnUIThread.Execute(() => + { + Verify.IsNotNull(Content); + }); + } + + [TestMethod] + public void VerifySelectedIndexChangedEventArgs() + { + PipsPager pager = null; + var previousIndex = -2; + var newIndex = -2; + RunOnUIThread.Execute(() => + { + pager = new PipsPager(); + pager.SelectedIndexChanged += Pager_SelectedIndexChanged; + Content = pager; + + }); + + IdleSynchronizer.Wait(); + + RunOnUIThread.Execute(() => + { + VerifySelectionChanged(-1, 0); + + pager.NumberOfPages = 10; + VerifySelectionChanged(-1, 0); + + pager.SelectedPageIndex = 9; + VerifySelectionChanged(0, 9); + + pager.SelectedPageIndex = 4; + VerifySelectionChanged(9, 4); + }); + + void Pager_SelectedIndexChanged(PipsPager sender, PipsPagerSelectedIndexChangedEventArgs args) + { + previousIndex = args.PreviousPageIndex; + newIndex = args.NewPageIndex; + } + + void VerifySelectionChanged(int expectedPreviousIndex, int expectedNewIndex) + { + Verify.AreEqual(expectedPreviousIndex, previousIndex, "Expected PreviousPageIndex:" + expectedPreviousIndex + ", actual: " + previousIndex); + Verify.AreEqual(expectedNewIndex, newIndex, "Expected PreviousPageIndex:" + expectedNewIndex + ", actual: " + newIndex); + } + } + } +} diff --git a/dev/PipsPager/APITests/PipsPager_APITests.projitems b/dev/PipsPager/APITests/PipsPager_APITests.projitems new file mode 100644 index 0000000000..1d24bd44f2 --- /dev/null +++ b/dev/PipsPager/APITests/PipsPager_APITests.projitems @@ -0,0 +1,14 @@ + + + + $(MSBuildAllProjects);$(MSBuildThisFileFullPath) + true + cb2352e2-d633-41a3-8cdc-b28731a4c490 + + + PipsPager_APITests + + + + + diff --git a/dev/PipsPager/APITests/PipsPager_APITests.shproj b/dev/PipsPager/APITests/PipsPager_APITests.shproj new file mode 100755 index 0000000000..854425119b --- /dev/null +++ b/dev/PipsPager/APITests/PipsPager_APITests.shproj @@ -0,0 +1,13 @@ + + + + {9CF0D73A-E435-4C17-A41C-11E9FA3EEA2F} + 14.0 + + + + + + + + \ No newline at end of file diff --git a/dev/PipsPager/InteractionTests/PipsPagerElements.cs b/dev/PipsPager/InteractionTests/PipsPagerElements.cs new file mode 100755 index 0000000000..2b18bb935c --- /dev/null +++ b/dev/PipsPager/InteractionTests/PipsPagerElements.cs @@ -0,0 +1,150 @@ +using Windows.UI.Xaml.Tests.MUXControls.InteractionTests.Common; +using Common; +using Microsoft.Windows.Apps.Test.Foundation; +using Microsoft.Windows.Apps.Test.Foundation.Controls; + +#if USING_TAEF +using WEX.TestExecution; +using WEX.TestExecution.Markup; +using WEX.Logging.Interop; +#else +using Microsoft.VisualStudio.TestTools.UnitTesting; +using Microsoft.VisualStudio.TestTools.UnitTesting.Logging; +#endif + +namespace Windows.UI.Xaml.Tests.MUXControls.InteractionTests +{ + public class PipsPagerElements + { + private UIObject PipsPager; + private UIObject NextPageButton; + private UIObject PreviousPageButton; + private ComboBox PreviousPageButtonVisibilityComboBox; + private ComboBox NextPageButtonVisibilityComboBox; + private ComboBox NumberOfPagesComboBox; + private ComboBox MaxVisualIndicatorsComboBox; + private ComboBox OrientationComboBox; + private CheckBox PreviousPageButtonIsVisibleCheckBox; + private CheckBox PreviousPageButtonIsEnabledCheckBox; + private CheckBox NextPageButtonIsVisibleCheckBox; + private CheckBox NextPageButtonIsEnabledCheckBox; + private TextBlock CurrentPageTextBlock; + private TextBlock CurrentNumberOfPagesTextBlock; + private TextBlock CurrentMaxVisualIndicatorsTextBlock; + private TextBlock CurrentOrientationTextBlock; + + public UIObject GetPipsPager() + { + return GetElement(ref PipsPager, "TestPipsPager"); + } + public UIObject GetPreviousPageButton() + { + return GetElementWithinPager(ref PreviousPageButton, "PreviousPageButton"); + } + + public UIObject GetNextPageButton() + { + return GetElementWithinPager(ref NextPageButton, "NextPageButton"); + } + + public ComboBox GetPreviousPageButtonVisibilityComboBox() + { + return GetElement(ref PreviousPageButtonVisibilityComboBox, "PreviousPageButtonVisibilityComboBox"); + } + + public ComboBox GetNextPageButtonVisibilityComboBox() + { + return GetElement(ref NextPageButtonVisibilityComboBox, "NextPageButtonVisibilityComboBox"); + } + + public CheckBox GetPreviousPageButtonIsVisibleCheckBox() + { + return GetElement(ref PreviousPageButtonIsVisibleCheckBox, "PreviousPageButtonIsVisibleCheckBox"); + } + public CheckBox GetPreviousPageButtonIsEnabledCheckBox() + { + return GetElement(ref PreviousPageButtonIsEnabledCheckBox, "PreviousPageButtonIsEnabledCheckBox"); + } + public CheckBox GetNextPageButtonIsVisibleCheckBox() + { + return GetElement(ref NextPageButtonIsVisibleCheckBox, "NextPageButtonIsVisibleCheckBox"); + } + public CheckBox GetNextPageButtonIsEnabledCheckBox() + { + return GetElement(ref NextPageButtonIsEnabledCheckBox, "NextPageButtonIsEnabledCheckBox"); + } + + public ComboBox GetNumberOfPagesComboBox() + { + return GetElement(ref NumberOfPagesComboBox, "TestPipsPagerNumberOfPagesComboBox"); + } + + public ComboBox GetMaxVisualIndicatorsComboBox() + { + return GetElement(ref MaxVisualIndicatorsComboBox, "TestPipsPagerMaxVisualIndicatorsComboBox"); + } + public ComboBox GetOrientationComboBox() + { + return GetElement(ref OrientationComboBox, "TestPipsPagerOrientationComboBox"); + } + public TextBlock GetCurrentPageTextBlock() + { + return GetElement(ref CurrentPageTextBlock, "CurrentPageIndexTextBlock"); + } + + public TextBlock GetCurrentMaxVisualIndicatorsTextBlock() + { + return GetElement(ref CurrentMaxVisualIndicatorsTextBlock, "CurrentMaxVisualIndicatorsTextBlock"); + } + + public TextBlock GetCurrentNumberOfPagesTextBlock() + { + return GetElement(ref CurrentNumberOfPagesTextBlock, "CurrentNumberOfPagesTextBlock"); + } + + public TextBlock GetCurrentOrientationTextBlock() + { + return GetElement(ref CurrentOrientationTextBlock, "CurrentOrientationTextBlock"); + } + + public UIObject GetPipWithPageNumber(string elementName) + { + foreach (var element in GetPipsPager().Children) + { + if (element.Name == elementName) + { + return element; + } + } + return null; + } + private T GetElement(ref T element, string elementName) where T : UIObject + { + if (element == null) + { + Log.Comment("Find the " + elementName); + element = FindElement.ByNameOrId(elementName); + Verify.IsNotNull(element); + } + return element; + } + private T GetElementWithinPager(ref T element, string elementName) where T : UIObject + { + if (element == null) + { + Log.Comment("Find the " + elementName); + + foreach (T child in GetPipsPager().Children) + { + if (child.AutomationId == elementName) + { + element = child; + break; + } + } + Verify.IsNotNull(element); + } + return element; + } + } +} diff --git a/dev/PipsPager/InteractionTests/PipsPagerTestBase.cs b/dev/PipsPager/InteractionTests/PipsPagerTestBase.cs new file mode 100755 index 0000000000..be2445073a --- /dev/null +++ b/dev/PipsPager/InteractionTests/PipsPagerTestBase.cs @@ -0,0 +1,187 @@ +using Common; +using Microsoft.Windows.Apps.Test.Automation; +#if USING_TAEF +using WEX.TestExecution; +using WEX.TestExecution.Markup; +using WEX.Logging.Interop; +#else +using Microsoft.VisualStudio.TestTools.UnitTesting; +using Microsoft.VisualStudio.TestTools.UnitTesting.Logging; +#endif +using System; +using System.Linq; +using Windows.UI.Xaml.Tests.MUXControls.InteractionTests.Common; + + +namespace Windows.UI.Xaml.Tests.MUXControls.InteractionTests +{ + public class PipsPagerTestBase + { + protected PipsPagerElements elements; + protected delegate void SetButtonVisibilityModeFunction(ButtonVisibilityMode mode); + protected delegate bool GetButtonIsHiddenOnEdgeFunction(); + + protected void SelectPageInPager(int index) + { + InputHelper.LeftClick(elements.GetPipWithPageNumber("Page " + index.ToString())); + Wait.ForIdle(); + } + + protected void VerifyPageButtonWithVisibilityModeSet(ButtonType btnType, ButtonVisibilityMode modeSet, bool isPagerInFocus = false) + { + ToggleState isVisibleState; + ToggleState isEnabledState; + bool isHiddenOnEdge; + + if (btnType == ButtonType.Previous) + { + isVisibleState = elements.GetPreviousPageButtonIsVisibleCheckBox().ToggleState; + isEnabledState = elements.GetPreviousPageButtonIsEnabledCheckBox().ToggleState; + isHiddenOnEdge = GetCurrentPageAsInt32() == 0; + } + else + { + isVisibleState = elements.GetNextPageButtonIsVisibleCheckBox().ToggleState; + isEnabledState = elements.GetNextPageButtonIsEnabledCheckBox().ToggleState; + isHiddenOnEdge = !(GetCurrentPage() == "Infinite") && GetCurrentPageAsInt32() == GetSelectedNumberOfPagesAsInt32() - 1; + } + switch (modeSet) + { + case ButtonVisibilityMode.Collapsed: + Verify.AreEqual(isVisibleState, ToggleState.Off); + Verify.AreEqual(isEnabledState, ToggleState.Off); + break; + + case ButtonVisibilityMode.Visible: + if (isHiddenOnEdge) + { + Verify.AreEqual(isVisibleState, ToggleState.Off); + Verify.AreEqual(isEnabledState, ToggleState.Off); + } + else + { + Verify.AreEqual(isVisibleState, ToggleState.On); + Verify.AreEqual(isEnabledState, ToggleState.On); + } + break; + + case ButtonVisibilityMode.VisibleOnHover: + if (isHiddenOnEdge) + { + Verify.AreEqual(isVisibleState, ToggleState.Off); + Verify.AreEqual(isEnabledState, ToggleState.Off); + } + else + { + if (isPagerInFocus) + { + Verify.AreEqual(isVisibleState, ToggleState.On); + } + else + { + Verify.AreEqual(isVisibleState, ToggleState.Off); + } + Verify.AreEqual(isEnabledState, ToggleState.On); + } + break; + } + } + + protected void VerifyNextPageButtonVisibility(Visibility expected) + { + Verify.AreEqual(expected == Visibility.Visible, elements.GetNextPageButtonIsVisibleCheckBox().ToggleState == ToggleState.On); + } + + protected void SetNextPageButtonVisibilityMode(ButtonVisibilityMode mode) + { + elements.GetNextPageButtonVisibilityComboBox().SelectItemByName($"{mode}NextButton"); + } + + protected void SetPreviousPageButtonVisibilityMode(ButtonVisibilityMode mode) + { + elements.GetPreviousPageButtonVisibilityComboBox().SelectItemByName($"{mode}PreviousButton"); + } + + protected void SetOrientation(OrientationType orientation) + { + elements.GetOrientationComboBox().SelectItemByName($"{orientation}Orientation"); + } + + protected void VerifyOrientationChanged(OrientationType orientation) + { + Verify.AreEqual($"{orientation}", GetCurrentOrientation()); + } + + protected void VerifyPageChanged(int expectedPage) + { + Verify.AreEqual(expectedPage, GetCurrentPageAsInt32()); + Log.Comment($"Changing to page {expectedPage}"); + } + + protected string GetCurrentOrientation() + { + return elements.GetCurrentOrientationTextBlock().GetText().Split(' ').Last(); + } + protected int GetCurrentPageAsInt32() + { + return Convert.ToInt32(GetCurrentPage()); + } + protected string GetCurrentPage() + { + string currentPageTextBlockContent = elements.GetCurrentPageTextBlock().GetText(); + return new string(currentPageTextBlockContent.Where(char.IsDigit).ToArray()); + } + + protected void ChangeNumberOfPages(NumberOfPagesOptions numberOfPages) + { + elements.GetNumberOfPagesComboBox().SelectItemByName($"{numberOfPages}NumberOfPages"); + } + + protected string GetSelectedNumberOfPages() + { + string selectedNumberOfPages = ExtractNumberFromString(elements.GetCurrentNumberOfPagesTextBlock().GetText()); + if (string.IsNullOrEmpty(selectedNumberOfPages)) + { + selectedNumberOfPages = "Infinite"; + } + return selectedNumberOfPages; + } + + protected int GetSelectedNumberOfPagesAsInt32() + { + return Convert.ToInt32(GetSelectedNumberOfPages()); + } + protected void VerifyNumberOfPages(string numberOfPages) + { + Verify.AreEqual(numberOfPages, GetSelectedNumberOfPages()); + + } + + private string ExtractNumberFromString(string text) + { + return new string(text.Where(char.IsDigit).ToArray()); + } + + public enum ButtonType + { + Previous, + Next + } + + public enum ButtonVisibilityMode + { + Visible, + VisibleOnHover, + Collapsed + } + + public enum NumberOfPagesOptions + { + Zero, + Five, + Ten, + Twenty, + Infinite + } + } +} diff --git a/dev/PipsPager/InteractionTests/PipsPagerTests.cs b/dev/PipsPager/InteractionTests/PipsPagerTests.cs new file mode 100755 index 0000000000..3a4bfb9ddf --- /dev/null +++ b/dev/PipsPager/InteractionTests/PipsPagerTests.cs @@ -0,0 +1,250 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. See LICENSE in the project root for license information. + + +using Windows.UI.Xaml.Tests.MUXControls.InteractionTests.Infra; +using Windows.UI.Xaml.Tests.MUXControls.InteractionTests.Common; +#if USING_TAEF +using WEX.TestExecution; +using WEX.TestExecution.Markup; +using WEX.Logging.Interop; +#else +using Microsoft.VisualStudio.TestTools.UnitTesting; +#endif + +namespace Windows.UI.Xaml.Tests.MUXControls.InteractionTests +{ + [TestClass] + public class PipsPagerTests : PipsPagerTestBase + { + [ClassInitialize] + [TestProperty("RunAs", "User")] + [TestProperty("Classification", "Integration")] + [TestProperty("Platform", "Any")] + [TestProperty("MUXControlsTestSuite", "SuiteB")] + public static void ClassInitialize(TestContext testContext) + { + TestEnvironment.Initialize(testContext); + } + + public void TestCleanup() + { + TestCleanupHelper.Cleanup(); + } + + [TestMethod] + [TestProperty("TestSuite", "A")] + public void PipsPagerChangingPageTest() + { + using (var setup = new TestSetupHelper("PipsPager Tests")) + { + elements = new PipsPagerElements(); + SetPreviousPageButtonVisibilityMode(ButtonVisibilityMode.Visible); + SetNextPageButtonVisibilityMode(ButtonVisibilityMode.Visible); + + VerifyPageChanged(0); + + InputHelper.LeftClick(elements.GetNextPageButton()); + VerifyPageChanged(1); + + InputHelper.LeftClick(elements.GetNextPageButton()); + VerifyPageChanged(2); + + InputHelper.LeftClick(elements.GetPreviousPageButton()); + VerifyPageChanged(1); + + InputHelper.LeftClick(elements.GetPreviousPageButton()); + VerifyPageChanged(0); + + ChangeNumberOfPages(NumberOfPagesOptions.Five); + VerifyNumberOfPages("5"); + + InputHelper.LeftClick(elements.GetNextPageButton()); + VerifyPageChanged(1); + + InputHelper.LeftClick(elements.GetNextPageButton()); + VerifyPageChanged(2); + + InputHelper.LeftClick(elements.GetNextPageButton()); + VerifyPageChanged(3); + + InputHelper.LeftClick(elements.GetPreviousPageButton()); + VerifyPageChanged(2); + } + } + + [TestMethod] + [TestProperty("TestSuite", "B")] + public void PreviousPageButtonChangingPageTest() + { + using (var setup = new TestSetupHelper("PipsPager Tests")) + { + elements = new PipsPagerElements(); + SetPreviousPageButtonVisibilityMode(ButtonVisibilityMode.Visible); + SetNextPageButtonVisibilityMode(ButtonVisibilityMode.Visible); + + VerifyPageChanged(0); + InputHelper.LeftClick(elements.GetNextPageButton()); + + InputHelper.LeftClick(elements.GetPreviousPageButton()); + VerifyPageChanged(0); + + InputHelper.LeftClick(elements.GetNextPageButton()); + InputHelper.LeftClick(elements.GetNextPageButton()); + + InputHelper.LeftClick(elements.GetPreviousPageButton()); + VerifyPageChanged(1); + } + } + + [TestMethod] + [TestProperty("TestSuite", "B")] + public void NextPageButtonChangingPageTest() + { + using (var setup = new TestSetupHelper("PipsPager Tests")) + { + elements = new PipsPagerElements(); + SetPreviousPageButtonVisibilityMode(ButtonVisibilityMode.Visible); + SetNextPageButtonVisibilityMode(ButtonVisibilityMode.Visible); + + VerifyPageChanged(0); + InputHelper.LeftClick(elements.GetNextPageButton()); + VerifyPageChanged(1); + + InputHelper.LeftClick(elements.GetNextPageButton()); + VerifyPageChanged(2); + + InputHelper.LeftClick(elements.GetNextPageButton()); + VerifyPageChanged(3); + + InputHelper.LeftClick(elements.GetNextPageButton()); + VerifyPageChanged(4); + } + } + + [TestMethod] + [TestProperty("TestSuite", "C")] + public void PipsPagerInfinitePagesTest() + { + using (var setup = new TestSetupHelper("PipsPager Tests")) + { + elements = new PipsPagerElements(); + SetPreviousPageButtonVisibilityMode(ButtonVisibilityMode.Visible); + SetNextPageButtonVisibilityMode(ButtonVisibilityMode.Visible); + + VerifyPageChanged(0); + + ChangeNumberOfPages(NumberOfPagesOptions.Infinite); + VerifyNumberOfPages("Infinite"); + + InputHelper.LeftClick(elements.GetNextPageButton()); + VerifyPageChanged(1); + + InputHelper.LeftClick(elements.GetNextPageButton()); + VerifyPageChanged(2); + + InputHelper.LeftClick(elements.GetNextPageButton()); + VerifyPageChanged(3); + + InputHelper.LeftClick(elements.GetNextPageButton()); + VerifyPageChanged(4); + + InputHelper.LeftClick(elements.GetNextPageButton()); + VerifyPageChanged(5); + + InputHelper.LeftClick(elements.GetNextPageButton()); + VerifyPageChanged(6); + + InputHelper.LeftClick(elements.GetNextPageButton()); + VerifyPageChanged(7); + } + } + + [TestMethod] + [TestProperty("TestSuite", "D")] + public void PreviousPageButtonVisibilityOptionsTest() + { + using (var setup = new TestSetupHelper("PipsPager Tests")) + { + elements = new PipsPagerElements(); + SetNextPageButtonVisibilityMode(ButtonVisibilityMode.Visible); + + /* Test for Collapsed */ + SetPreviousPageButtonVisibilityMode(ButtonVisibilityMode.Collapsed); + VerifyPageButtonWithVisibilityModeSet(ButtonType.Previous, ButtonVisibilityMode.Collapsed); + InputHelper.LeftClick(elements.GetNextPageButton()); + VerifyPageButtonWithVisibilityModeSet(ButtonType.Previous, ButtonVisibilityMode.Collapsed); + + /* Test for Visible */ + SetPreviousPageButtonVisibilityMode(ButtonVisibilityMode.Visible); + VerifyPageButtonWithVisibilityModeSet(ButtonType.Previous, ButtonVisibilityMode.Visible); + InputHelper.LeftClick(elements.GetPreviousPageButton()); + VerifyPageButtonWithVisibilityModeSet(ButtonType.Previous, ButtonVisibilityMode.Collapsed); + + /* Test for VisibleOnHover */ + SetPreviousPageButtonVisibilityMode(ButtonVisibilityMode.VisibleOnHover); + VerifyPageButtonWithVisibilityModeSet(ButtonType.Previous, ButtonVisibilityMode.Collapsed); + + InputHelper.LeftClick(elements.GetNextPageButton()); + VerifyPageButtonWithVisibilityModeSet(ButtonType.Previous, ButtonVisibilityMode.VisibleOnHover, true); + + InputHelper.LeftClick(elements.GetCurrentNumberOfPagesTextBlock()); + VerifyPageButtonWithVisibilityModeSet(ButtonType.Previous, ButtonVisibilityMode.VisibleOnHover); + } + } + + [TestMethod] + [TestProperty("TestSuite", "D")] + public void NextPageButtonVisibilityOptionsTest() + { + using (var setup = new TestSetupHelper("PipsPager Tests")) + { + elements = new PipsPagerElements(); + SetPreviousPageButtonVisibilityMode(ButtonVisibilityMode.VisibleOnHover); + + ChangeNumberOfPages(NumberOfPagesOptions.Five); + VerifyNumberOfPages("5"); + + /* Test for Collapsed */ + SetNextPageButtonVisibilityMode(ButtonVisibilityMode.Collapsed); + VerifyPageButtonWithVisibilityModeSet(ButtonType.Next, ButtonVisibilityMode.Collapsed); + + /* Test for Visible */ + SetNextPageButtonVisibilityMode(ButtonVisibilityMode.Visible); + VerifyPageButtonWithVisibilityModeSet(ButtonType.Next, ButtonVisibilityMode.Visible); + /* We step until the end of the list (4 times, since we have 5 pages) */ + InputHelper.LeftClick(elements.GetNextPageButton()); + InputHelper.LeftClick(elements.GetNextPageButton()); + InputHelper.LeftClick(elements.GetNextPageButton()); + InputHelper.LeftClick(elements.GetNextPageButton()); + VerifyPageButtonWithVisibilityModeSet(ButtonType.Next, ButtonVisibilityMode.Collapsed); + + /* Test for VisibleOnHover */ + SetNextPageButtonVisibilityMode(ButtonVisibilityMode.VisibleOnHover); + VerifyPageButtonWithVisibilityModeSet(ButtonType.Next, ButtonVisibilityMode.Collapsed); + + InputHelper.LeftClick(elements.GetPreviousPageButton()); + VerifyPageButtonWithVisibilityModeSet(ButtonType.Next, ButtonVisibilityMode.VisibleOnHover, true); + + InputHelper.LeftClick(elements.GetCurrentNumberOfPagesTextBlock()); + VerifyPageButtonWithVisibilityModeSet(ButtonType.Next, ButtonVisibilityMode.VisibleOnHover); + } + } + + [TestMethod] + [TestProperty("TestSuite", "E")] + public void OrientationChangeTest() + { + using (var setup = new TestSetupHelper("PipsPager Tests")) + { + elements = new PipsPagerElements(); + SetOrientation(Microsoft.Windows.Apps.Test.Automation.OrientationType.Horizontal); + VerifyOrientationChanged(Microsoft.Windows.Apps.Test.Automation.OrientationType.Horizontal); + + SetOrientation(Microsoft.Windows.Apps.Test.Automation.OrientationType.Vertical); + VerifyOrientationChanged(Microsoft.Windows.Apps.Test.Automation.OrientationType.Vertical); + + } + } + } +} diff --git a/dev/PipsPager/InteractionTests/PipsPager_InteractionTests.projitems b/dev/PipsPager/InteractionTests/PipsPager_InteractionTests.projitems new file mode 100755 index 0000000000..7156eb9c94 --- /dev/null +++ b/dev/PipsPager/InteractionTests/PipsPager_InteractionTests.projitems @@ -0,0 +1,17 @@ + + + + + $(MSBuildAllProjects);$(MSBuildThisFileFullPath) + true + A1553559-5786-4B44-AB9E-94AB95C86D4D + + + PipsPager_InteractionTests + + + + + + + \ No newline at end of file diff --git a/dev/PipsPager/InteractionTests/PipsPager_InteractionTests.shproj b/dev/PipsPager/InteractionTests/PipsPager_InteractionTests.shproj new file mode 100755 index 0000000000..4398bd0e95 --- /dev/null +++ b/dev/PipsPager/InteractionTests/PipsPager_InteractionTests.shproj @@ -0,0 +1,14 @@ + + + + + {B1D8E6A2-3FE6-4D80-9685-26DF2C9F4331} + 15.0 + + + + + + + + \ No newline at end of file diff --git a/dev/PipsPager/PipsPager.cpp b/dev/PipsPager/PipsPager.cpp new file mode 100755 index 0000000000..cc61065ca0 --- /dev/null +++ b/dev/PipsPager/PipsPager.cpp @@ -0,0 +1,578 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. See LICENSE in the project root for license information. + +#include "pch.h" +#include "common.h" +#include "Vector.h" +#include "PipsPager.h" +#include "RuntimeProfiler.h" +#include "ResourceAccessor.h" +#include "PipsPagerTemplateSettings.h" +#include "PipsPagerSelectedIndexChangedEventArgs.h" +#include "PipsPagerAutomationPeer.h" + +typedef winrt::PipsPagerButtonVisibility ButtonVisibility; + +static constexpr wstring_view s_pipButtonHandlersPropertyName = L"PipButtonHandlers"sv; + +constexpr auto c_previousPageButtonVisibleVisualState = L"PreviousPageButtonVisible"sv; +constexpr auto c_previousPageButtonHiddenVisualState = L"PreviousPageButtonHidden"sv; +constexpr auto c_previousPageButtonCollapsedVisualState = L"PreviousPageButtonCollapsed"sv; + +constexpr auto c_previousPageButtonEnabledVisualState = L"PreviousPageButtonEnabled"sv; +constexpr auto c_previousPageButtonDisabledVisualState = L"PreviousPageButtonDisabled"sv; + +constexpr auto c_nextPageButtonVisibleVisualState = L"NextPageButtonVisible"sv; +constexpr auto c_nextPageButtonHiddenVisualState = L"NextPageButtonHidden"sv; +constexpr auto c_nextPageButtonCollapsedVisualState = L"NextPageButtonCollapsed"sv; + +constexpr auto c_nextPageButtonEnabledVisualState = L"NextPageButtonEnabled"sv; +constexpr auto c_nextPageButtonDisabledVisualState = L"NextPageButtonDisabled"sv; + +constexpr auto c_previousPageButtonName = L"PreviousPageButton"sv; +constexpr auto c_nextPageButtonName = L"NextPageButton"sv; + +constexpr auto c_pipsPagerRepeaterName = L"PipsPagerItemsRepeater"sv; +constexpr auto c_pipsPagerScrollViewerName = L"PipsPagerScrollViewer"sv; + +constexpr auto c_pipsPagerButtonWidthPropertyName = L"PipsPagerButtonWidth"sv; +constexpr auto c_pipsPagerButtonHeightPropertyName = L"PipsPagerButtonHeight"sv; + +constexpr auto c_pipsPagerHorizontalOrientationVisualState = L"HorizontalOrientationView"sv; +constexpr auto c_pipsPagerVerticalOrientationVisualState = L"VerticalOrientationView"sv; + +PipsPager::PipsPager() +{ + __RP_Marker_ClassById(RuntimeProfiler::ProfId_PipsPager); + + m_pipsPagerItems = winrt::make>().as>(); + const auto templateSettings = winrt::make(); + templateSettings.SetValue(PipsPagerTemplateSettings::s_PipsPagerItemsProperty, m_pipsPagerItems); + SetValue(s_TemplateSettingsProperty, templateSettings); + + s_pipButtonHandlersProperty = + InitializeDependencyProperty( + s_pipButtonHandlersPropertyName, + winrt::name_of(), + winrt::name_of(), + true, + nullptr, + nullptr); + SetDefaultStyleKey(this); +} + +void PipsPager::OnApplyTemplate() +{ + winrt::AutomationProperties::SetName(*this, ResourceAccessor::GetLocalizedStringResource(SR_PipsPagerNameText)); + + m_previousPageButtonClickRevoker.revoke(); + [this](const winrt::Button button) + { + if (button) + { + winrt::AutomationProperties::SetName(button, ResourceAccessor::GetLocalizedStringResource(SR_PipsPagerPreviousPageButtonText)); + m_previousPageButtonClickRevoker = button.Click(winrt::auto_revoke, { this, &PipsPager::OnPreviousButtonClicked }); + } + }(GetTemplateChildT(c_previousPageButtonName, *this)); + + m_nextPageButtonClickRevoker.revoke(); + [this](const winrt::Button button) + { + if (button) + { + winrt::AutomationProperties::SetName(button, ResourceAccessor::GetLocalizedStringResource(SR_PipsPagerNextPageButtonText)); + m_nextPageButtonClickRevoker = button.Click(winrt::auto_revoke, { this, &PipsPager::OnNextButtonClicked }); + } + }(GetTemplateChildT(c_nextPageButtonName, *this)); + + m_pipsPagerElementPreparedRevoker.revoke(); + [this](const winrt::ItemsRepeater repeater) + { + m_pipsPagerRepeater.set(repeater); + if (repeater) + { + m_pipsPagerElementPreparedRevoker = repeater.ElementPrepared(winrt::auto_revoke, { this, &PipsPager::OnElementPrepared }); + } + }(GetTemplateChildT(c_pipsPagerRepeaterName, *this)); + + m_pipsPagerScrollViewer.set(GetTemplateChildT(c_pipsPagerScrollViewerName, *this)); + + m_defaultPipSize = GetDesiredPipSize(DefaultIndicatorButtonStyle()); + m_selectedPipSize = GetDesiredPipSize(SelectedIndicatorButtonStyle()); + OnNavigationButtonVisibilityChanged(PreviousButtonVisibility(), c_previousPageButtonCollapsedVisualState, c_previousPageButtonDisabledVisualState); + OnNavigationButtonVisibilityChanged(NextButtonVisibility(), c_nextPageButtonCollapsedVisualState, c_nextPageButtonDisabledVisualState); + UpdatePipsItems(NumberOfPages(), MaxVisualIndicators()); + OnOrientationChanged(); + OnSelectedPageIndexChanged(m_lastSelectedPageIndex); +} + +void PipsPager::RaiseSelectedIndexChanged() +{ + const auto args = winrt::make_self(m_lastSelectedPageIndex, SelectedPageIndex()); + m_selectedIndexChangedEventSource(*this, *args); +} + +winrt::Size PipsPager::GetDesiredPipSize(const winrt::Style& style) { + if (auto const repeater = m_pipsPagerRepeater.get()) + { + if (auto const itemTemplate = repeater.ItemTemplate().try_as()) + { + if (auto const element = itemTemplate.LoadContent().try_as()) + { + element.Style(style); + element.Measure({ std::numeric_limits::infinity(), std::numeric_limits::infinity() }); + return element.DesiredSize(); + } + } + } + /* Extract default sizes and return in case the code above fails */ + auto pipHeight = unbox_value(ResourceAccessor::ResourceLookup(*this, box_value(c_pipsPagerButtonHeightPropertyName))); + auto pipWidth = unbox_value(ResourceAccessor::ResourceLookup(*this, box_value(c_pipsPagerButtonWidthPropertyName))); + return { static_cast(pipWidth), static_cast(pipHeight) }; +} + +void PipsPager::OnKeyDown(const winrt::KeyRoutedEventArgs& args) { + winrt::FocusNavigationDirection previousPipDirection; + winrt::FocusNavigationDirection nextPipDirection; + if (Orientation() == winrt::Orientation::Vertical) + { + previousPipDirection = winrt::FocusNavigationDirection::Up; + nextPipDirection = winrt::FocusNavigationDirection::Down; + } + else + { + previousPipDirection = winrt::FocusNavigationDirection::Left; + nextPipDirection = winrt::FocusNavigationDirection::Right; + } + + if (args.Key() == winrt::VirtualKey::Left || args.Key() == winrt::VirtualKey::Up) + { + winrt::FocusManager::TryMoveFocus(previousPipDirection); + args.Handled(true); + } + else if (args.Key() == winrt::VirtualKey::Right || args.Key() == winrt::VirtualKey::Down) + { + winrt::FocusManager::TryMoveFocus(nextPipDirection); + args.Handled(true); + } + // Call for all other presses + __super::OnKeyDown(args); +} + +void PipsPager::OnPointerEntered(const winrt::PointerRoutedEventArgs& args) { + __super::OnPointerEntered(args); + m_isPointerOver = true; + UpdateNavigationButtonVisualStates(); +} +void PipsPager::OnPointerExited(const winrt::PointerRoutedEventArgs& args) { + // We can get a spurious Exited and then Entered if the button + // that is being clicked on hides itself. In order to avoid switching + // visual states in this case, we check if the pointer is over the + // control bounds when we get the exited event. + if (IsOutOfControlBounds(args.GetCurrentPoint(*this).Position())) + { + m_isPointerOver = false; + UpdateNavigationButtonVisualStates(); + } + else + { + args.Handled(true); + } + __super::OnPointerExited(args); +} + +void PipsPager::OnPointerCanceled(const winrt::PointerRoutedEventArgs& args) +{ + __super::OnPointerCanceled(args); + m_isPointerOver = false; + UpdateNavigationButtonVisualStates(); +} + +bool PipsPager::IsOutOfControlBounds(const winrt::Point& point) { + // This is a conservative check. It is okay to say we are + // out of the bounds when close to the edge to account for rounding. + const auto tolerance = 1.0; + const auto actualWidth = ActualWidth(); + const auto actualHeight = ActualHeight(); + return point.X < tolerance || + point.X > actualWidth - tolerance || + point.Y < tolerance || + point.Y > actualHeight - tolerance; +} + +void PipsPager::UpdateIndividualNavigationButtonVisualState( + const bool hiddenOnEdgeCondition, + const ButtonVisibility visibility, + const wstring_view& visibleStateName, + const wstring_view& hiddenStateName, + const wstring_view& enabledStateName, + const wstring_view& disabledStateName) { + + const auto ifGenerallyVisible = !hiddenOnEdgeCondition && NumberOfPages() != 0 && MaxVisualIndicators() > 0; + if (visibility != ButtonVisibility::Collapsed) + { + if ((visibility == ButtonVisibility::Visible || m_isPointerOver) && ifGenerallyVisible) + { + winrt::VisualStateManager::GoToState(*this, visibleStateName, false); + winrt::VisualStateManager::GoToState(*this, enabledStateName, false); + } + else + { + if (!ifGenerallyVisible) + { + winrt::VisualStateManager::GoToState(*this, disabledStateName, false); + } + else + { + winrt::VisualStateManager::GoToState(*this, enabledStateName, false); + } + winrt::VisualStateManager::GoToState(*this, hiddenStateName, false); + } + } +} + +void PipsPager::UpdateNavigationButtonVisualStates() { + const int selectedPageIndex = SelectedPageIndex(); + const int numberOfPages = NumberOfPages(); + + auto const ifPreviousButtonHiddenOnEdge = selectedPageIndex == 0; + UpdateIndividualNavigationButtonVisualState(ifPreviousButtonHiddenOnEdge, PreviousButtonVisibility(), + c_previousPageButtonVisibleVisualState, c_previousPageButtonHiddenVisualState, + c_previousPageButtonEnabledVisualState, c_previousPageButtonDisabledVisualState); + + auto const ifNextButtonHiddenOnEdge = selectedPageIndex == numberOfPages - 1; + UpdateIndividualNavigationButtonVisualState(ifNextButtonHiddenOnEdge, NextButtonVisibility(), + c_nextPageButtonVisibleVisualState, c_nextPageButtonHiddenVisualState, + c_nextPageButtonEnabledVisualState, c_nextPageButtonDisabledVisualState); +} + +void PipsPager::ScrollToCenterOfViewport(const winrt::UIElement sender, const int index) +{ + /* Vertical and Horizontal AligmentsRatio are not available until Win Version 1803 (sdk version 17134) */ + if (SharedHelpers::IsBringIntoViewOptionsVerticalAlignmentRatioAvailable()) + { + winrt::BringIntoViewOptions options; + options.VerticalAlignmentRatio(0.5); + options.HorizontalAlignmentRatio(0.5); + options.AnimationDesired(true); + sender.StartBringIntoView(options); + } + else if (const auto scrollViewer = m_pipsPagerScrollViewer.get()) + { + double pipSize; + std::function changeViewFunc; + if (Orientation() == winrt::Orientation::Horizontal) + { + pipSize = m_defaultPipSize.Width; + changeViewFunc = [&](const double& offset) {scrollViewer.ChangeView(offset, nullptr, nullptr);}; + } + else + { + pipSize = m_defaultPipSize.Height; + changeViewFunc = [&](const double& offset) {scrollViewer.ChangeView(nullptr, offset, nullptr);}; + } + const int maxVisualIndicators = MaxVisualIndicators(); + /* This line makes sure that while having even # of indicators the scrolling will be done correctly */ + const int offSetChangeForEvenSizeWindow = maxVisualIndicators % 2 == 0 && index > m_lastSelectedPageIndex ? 1 : 0; + const int offSetNumOfElements = index + offSetChangeForEvenSizeWindow - maxVisualIndicators / 2; + const double offset = std::max(0.0, offSetNumOfElements * pipSize); + changeViewFunc(offset); + } +} + +void PipsPager::UpdateSelectedPip(const int index) { + if (NumberOfPages() != 0 && MaxVisualIndicators() > 0) + { + if (const auto repeater = m_pipsPagerRepeater.get()) + { + repeater.UpdateLayout(); + if (const auto element = repeater.TryGetElement(m_lastSelectedPageIndex).try_as()) + { + element.Style(DefaultIndicatorButtonStyle()); + } + if (const auto element = repeater.GetOrCreateElement(index).try_as()) + { + element.Style(SelectedIndicatorButtonStyle()); + ScrollToCenterOfViewport(element, index); + } + } + } +} + +double PipsPager::CalculateScrollViewerSize(const double defaultPipSize, const double selectedPipSize, const int numberOfPages, int maxVisualIndicators) { + + auto numberOfPagesToDisplay = 0; + maxVisualIndicators = std::max(0, maxVisualIndicators); + if (maxVisualIndicators == 0 || numberOfPages == 0) { + return 0; + } + else if (numberOfPages > 0) + { + numberOfPagesToDisplay = std::min(maxVisualIndicators, numberOfPages); + } + else + { + numberOfPagesToDisplay = maxVisualIndicators; + } + return defaultPipSize * (numberOfPagesToDisplay - 1) + selectedPipSize; +} + +void PipsPager::SetScrollViewerMaxSize() { + if (const auto scrollViewer = m_pipsPagerScrollViewer.get()) + { + if (Orientation() == winrt::Orientation::Horizontal) + { + const auto scrollViewerWidth = CalculateScrollViewerSize(m_defaultPipSize.Width, m_selectedPipSize.Width, NumberOfPages(), MaxVisualIndicators()); + scrollViewer.MaxWidth(scrollViewerWidth); + scrollViewer.MaxHeight(std::max(m_defaultPipSize.Height, m_selectedPipSize.Height)); + } + else + { + const auto scrollViewerHeight = CalculateScrollViewerSize(m_defaultPipSize.Height, m_selectedPipSize.Height, NumberOfPages(), MaxVisualIndicators()); + scrollViewer.MaxHeight(scrollViewerHeight); + scrollViewer.MaxWidth(std::max(m_defaultPipSize.Width, m_selectedPipSize.Width)); + } + } +} + +void PipsPager::UpdatePipsItems(const int numberOfPages, int maxVisualIndicators) { + auto const pipsListSize = int(m_pipsPagerItems.Size()); + + if (numberOfPages == 0 || maxVisualIndicators == 0) + { + m_pipsPagerItems.Clear(); + } + /* Inifinite number of pages case */ + else if (numberOfPages < 0) + { + /* Treat negative max visual indicators as 0*/ + auto const minNumberOfElements = std::max(SelectedPageIndex() + 1, std::max(0, maxVisualIndicators)); + if (minNumberOfElements > pipsListSize) + { + for (int i = pipsListSize; i < minNumberOfElements; i++) + { + m_pipsPagerItems.Append(winrt::box_value(i + 1)); + } + } + else if (SelectedPageIndex() == pipsListSize - 1) { + m_pipsPagerItems.Append(winrt::box_value(pipsListSize + 1)); + } + } + else if (pipsListSize < numberOfPages) + { + for (int i = pipsListSize; i < numberOfPages; i++) + { + m_pipsPagerItems.Append(winrt::box_value(i + 1)); + } + } + else { + for (int i = numberOfPages; i < pipsListSize; i++) + { + m_pipsPagerItems.RemoveAtEnd(); + } + } +} + +void PipsPager::OnElementPrepared(winrt::ItemsRepeater sender, winrt::ItemsRepeaterElementPreparedEventArgs args) +{ + if (auto const element = args.Element()) + { + if (const auto pip = element.try_as()) + { + auto const index = args.Index(); + if (index != SelectedPageIndex()) + { + pip.Style(DefaultIndicatorButtonStyle()); + } + + // Narrator says: Page 5, Button 5 of 30. Is it expected behavior? + winrt::AutomationProperties::SetName(pip, ResourceAccessor::GetLocalizedStringResource(SR_PipsPagerPageText) + L" " + winrt::to_hstring(index + 1)); + winrt::AutomationProperties::SetPositionInSet(pip, index + 1); + winrt::AutomationProperties::SetSizeOfSet(pip, NumberOfPages()); + + auto pciRevokers = winrt::make_self(); + pciRevokers->clickRevoker = pip.Click(winrt::auto_revoke, + [this, index](auto const& sender, auto const& args) + { + if (const auto repeater = m_pipsPagerRepeater.get()) { + if (const auto button = sender.try_as()) + { + SelectedPageIndex(repeater.GetElementIndex(button)); + } + } + } + ); + pip.SetValue(s_pipButtonHandlersProperty, pciRevokers.as()); + } + } +} + +void PipsPager::OnElementIndexChanged(const winrt::ItemsRepeater&, const winrt::ItemsRepeaterElementIndexChangedEventArgs& args) +{ + if (auto const pip = args.Element()) + { + auto const newIndex = args.NewIndex(); + winrt::AutomationProperties::SetName(pip, ResourceAccessor::GetLocalizedStringResource(SR_PipsPagerPageText) + L" " + winrt::to_hstring(newIndex + 1)); + winrt::AutomationProperties::SetPositionInSet(pip, newIndex + 1); + } +} + +void PipsPager::OnMaxVisualIndicatorsChanged() +{ + const auto numberOfPages = NumberOfPages(); + if (numberOfPages < 0) { + UpdatePipsItems(numberOfPages, MaxVisualIndicators()); + } + SetScrollViewerMaxSize(); + UpdateSelectedPip(SelectedPageIndex()); + UpdateNavigationButtonVisualStates(); +} + +void PipsPager::OnNumberOfPagesChanged() +{ + const int numberOfPages = NumberOfPages(); + const int selectedPageIndex = SelectedPageIndex(); + UpdateSizeOfSetForElements(numberOfPages); + UpdatePipsItems(numberOfPages, MaxVisualIndicators()); + SetScrollViewerMaxSize(); + if (SelectedPageIndex() > numberOfPages - 1 && numberOfPages > -1) + { + SelectedPageIndex(numberOfPages - 1); + } + else + { + UpdateSelectedPip(selectedPageIndex); + UpdateNavigationButtonVisualStates(); + } +} + +void PipsPager::OnSelectedPageIndexChanged(const int oldValue) +{ + // If we don't have any pages, there is nothing we should do. + // Ensure that SelectedPageIndex will end up in the valid range of values + // Special case is NumberOfPages being 0, in that case, don't verify upperbound restrictions + if (SelectedPageIndex() > NumberOfPages() - 1 && NumberOfPages() > 0) + { + SelectedPageIndex(NumberOfPages() - 1); + } + else if (SelectedPageIndex() < 0) + { + SelectedPageIndex(0); + } + else { + // Now handle the value changes + m_lastSelectedPageIndex = oldValue; + + // Fire value property change for UIA + if (const auto peer = winrt::FrameworkElementAutomationPeer::FromElement(*this).try_as()) + { + winrt::get_self(peer)->RaiseSelectionChanged(m_lastSelectedPageIndex, SelectedPageIndex()); + } + if (NumberOfPages() < 0) { + UpdatePipsItems(NumberOfPages(), MaxVisualIndicators()); + } + UpdateSelectedPip(SelectedPageIndex()); + UpdateNavigationButtonVisualStates(); + RaiseSelectedIndexChanged(); + } +} + +void PipsPager::OnOrientationChanged() +{ + if (Orientation() == winrt::Orientation::Horizontal) + { + winrt::VisualStateManager::GoToState(*this, c_pipsPagerHorizontalOrientationVisualState, false); + } + else + { + winrt::VisualStateManager::GoToState(*this, c_pipsPagerVerticalOrientationVisualState, false); + } + SetScrollViewerMaxSize(); + UpdateSelectedPip(SelectedPageIndex()); + +} + +void PipsPager::OnNavigationButtonVisibilityChanged(const ButtonVisibility visibility, const wstring_view& collapsedStateName, const wstring_view& disabledStateName) { + if (visibility == ButtonVisibility::Collapsed) + { + winrt::VisualStateManager::GoToState(*this, collapsedStateName, false); + winrt::VisualStateManager::GoToState(*this, disabledStateName, false); + } + else + { + UpdateNavigationButtonVisualStates(); + } +} + +void PipsPager::OnPreviousButtonClicked(const IInspectable& sender, const winrt::RoutedEventArgs& e) +{ + // In this method, SelectedPageIndex is always greater than 0. + SelectedPageIndex(SelectedPageIndex() - 1); +} + +void PipsPager::OnNextButtonClicked(const IInspectable& sender, const winrt::RoutedEventArgs& e) +{ + // In this method, SelectedPageIndex is always less than maximum. + SelectedPageIndex(SelectedPageIndex() + 1); +} + +void PipsPager::OnPropertyChanged(const winrt::DependencyPropertyChangedEventArgs& args) +{ + winrt::IDependencyProperty property = args.Property(); + if (this->Template() != nullptr) + { + if (property == NumberOfPagesProperty()) + { + OnNumberOfPagesChanged(); + } + else if (property == SelectedPageIndexProperty()) + { + OnSelectedPageIndexChanged(winrt::unbox_value(args.OldValue())); + } + else if (property == MaxVisualIndicatorsProperty()) { + OnMaxVisualIndicatorsChanged(); + } + else if (property == PreviousButtonVisibilityProperty()) + { + OnNavigationButtonVisibilityChanged(PreviousButtonVisibility(), c_previousPageButtonCollapsedVisualState, c_previousPageButtonDisabledVisualState); + } + else if (property == NextButtonVisibilityProperty()) + { + OnNavigationButtonVisibilityChanged(NextButtonVisibility(), c_nextPageButtonCollapsedVisualState, c_nextPageButtonDisabledVisualState); + } + else if (property == DefaultIndicatorButtonStyleProperty()) + { + m_defaultPipSize = GetDesiredPipSize(DefaultIndicatorButtonStyle()); + SetScrollViewerMaxSize(); + UpdateSelectedPip(SelectedPageIndex()); + } + else if (property == SelectedIndicatorButtonStyleProperty()) + { + m_selectedPipSize = GetDesiredPipSize(SelectedIndicatorButtonStyle()); + SetScrollViewerMaxSize(); + UpdateSelectedPip(SelectedPageIndex()); + } + else if (property == OrientationProperty()) + { + OnOrientationChanged(); + } + } +} + +winrt::AutomationPeer PipsPager::OnCreateAutomationPeer() +{ + return winrt::make(*this); +} + +void PipsPager::UpdateSizeOfSetForElements(const int numberOfPages) { + if(auto const repeater = m_pipsPagerRepeater.get()) + { + for (int i = 0; i < numberOfPages; i++) + { + if (auto const pip = repeater.TryGetElement(i)) + { + winrt::AutomationProperties::SetSizeOfSet(pip, numberOfPages); + } + } + } +} diff --git a/dev/PipsPager/PipsPager.h b/dev/PipsPager/PipsPager.h new file mode 100755 index 0000000000..4e484b3f45 --- /dev/null +++ b/dev/PipsPager/PipsPager.h @@ -0,0 +1,96 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. See LICENSE in the project root for license information. + +#pragma once + +#include "pch.h" +#include "common.h" +#include "PipsPager.g.h" +#include "PipsPager.properties.h" + +class PipsPagerViewItemRevokers : public winrt::implements +{ +public: + winrt::Button::Click_revoker clickRevoker{}; +}; + +class PipsPager : + public ReferenceTracker, + public PipsPagerProperties +{ +public: + PipsPager(); + + /* IFrameworkElement */ + void OnApplyTemplate(); + void OnPropertyChanged(const winrt::DependencyPropertyChangedEventArgs& args); + + /* Accessibility */ + winrt::AutomationPeer OnCreateAutomationPeer(); + void UpdateSizeOfSetForElements(const int numberOfPages); + + void OnPointerEntered(const winrt::PointerRoutedEventArgs& args); + void OnPointerExited(const winrt::PointerRoutedEventArgs& args); + void OnPointerCanceled(const winrt::PointerRoutedEventArgs& args); + void OnKeyDown(const winrt::KeyRoutedEventArgs& args); + + /* Property changed handlers */ + void OnNumberOfPagesChanged(); + void OnSelectedPageIndexChanged(const int oldValue); + void OnMaxVisualIndicatorsChanged(); + void OnNavigationButtonVisibilityChanged( + const winrt::PipsPagerButtonVisibility visibility, + const wstring_view& collapsedStateName, + const wstring_view& disabledStateName); + void OnOrientationChanged(); + + /* Dependency property for pip buttons revokers */ + GlobalDependencyProperty s_pipButtonHandlersProperty; + +private: + /* UI updating */ + void UpdateNavigationButtonVisualStates(); + void SetScrollViewerMaxSize(); + bool IsOutOfControlBounds(const winrt::Point& point); + void UpdateIndividualNavigationButtonVisualState( + const bool hiddenOnEdgeCondition, + const winrt::PipsPagerButtonVisibility visibility, + const wstring_view& visibleStateName, + const wstring_view& hiddenStateName, + const wstring_view& enabledStateName, + const wstring_view& disabledStateName); + winrt::Size GetDesiredPipSize(const winrt::Style& style); + void ScrollToCenterOfViewport(const winrt::UIElement sender, const int index); + double CalculateScrollViewerSize(const double defaultPipSize, const double selectedPipSize, const int numberOfPages, int maxVisualIndicators); + void UpdateSelectedPip(const int index); + + /* Eventing */ + void RaiseSelectedIndexChanged(); + + /* Interaction event listeners */ + void OnPreviousButtonClicked(const IInspectable& sender, const winrt::RoutedEventArgs& args); + void OnNextButtonClicked(const IInspectable& sender, const winrt::RoutedEventArgs& args); + + /* Pips Logic */ + void UpdatePipsItems(const int numberOfPages, int maxVisualIndicators); + void OnElementPrepared(winrt::ItemsRepeater sender, winrt::ItemsRepeaterElementPreparedEventArgs args); + void OnElementIndexChanged(const winrt::ItemsRepeater& repeater, const winrt::ItemsRepeaterElementIndexChangedEventArgs& args); + + /* Refs */ + tracker_ref m_pipsPagerRepeater{ this }; + tracker_ref m_pipsPagerScrollViewer{ this }; + + /* Revokers */ + winrt::Button::Click_revoker m_previousPageButtonClickRevoker{}; + winrt::Button::Click_revoker m_nextPageButtonClickRevoker{}; + winrt::ItemsRepeater::ElementPrepared_revoker m_pipsPagerElementPreparedRevoker{}; + + /* Items */ + winrt::IObservableVector m_pipsPagerItems{}; + + /* Additional variables class variables*/ + winrt::Size m_defaultPipSize{ 0.0,0.0 }; + winrt::Size m_selectedPipSize{ 0.0, 0.0 }; + int m_lastSelectedPageIndex{ -1 }; + bool m_isPointerOver{ false }; +}; diff --git a/dev/PipsPager/PipsPager.idl b/dev/PipsPager/PipsPager.idl new file mode 100755 index 0000000000..0818b68307 --- /dev/null +++ b/dev/PipsPager/PipsPager.idl @@ -0,0 +1,78 @@ +namespace MU_XC_NAMESPACE +{ + +[WUXC_VERSION_PREVIEW] +[webhosthidden] +enum PipsPagerButtonVisibility +{ + Visible, + VisibleOnHover, + Collapsed +}; + +[WUXC_VERSION_PREVIEW] +[webhosthidden] +runtimeclass PipsPagerSelectedIndexChangedEventArgs +{ + Int32 NewPageIndex{get; }; + Int32 PreviousPageIndex{get; }; +}; + +[WUXC_VERSION_PREVIEW] +[webhosthidden] +[MUX_PROPERTY_NEEDS_DP_FIELD] +unsealed runtimeclass PipsPagerTemplateSettings : Windows.UI.Xaml.DependencyObject +{ + PipsPagerTemplateSettings(); + Windows.Foundation.Collections.IVector PipsPagerItems { get; }; +}; + +[WUXC_VERSION_PREVIEW] +[webhosthidden] +[MUX_PROPERTY_CHANGED_CALLBACK(TRUE)] +[MUX_PROPERTY_CHANGED_CALLBACK_METHODNAME("OnPropertyChanged")] +unsealed runtimeclass PipsPager : Windows.UI.Xaml.Controls.Control +{ + PipsPager(); + + [MUX_DEFAULT_VALUE("-1")] + Int32 NumberOfPages; + + [MUX_DEFAULT_VALUE("0")] + Int32 SelectedPageIndex; + + [MUX_DEFAULT_VALUE("5")] + Int32 MaxVisualIndicators; + + [MUX_DEFAULT_VALUE("winrt::Orientation::Horizontal")] + Windows.UI.Xaml.Controls.Orientation Orientation; + + [MUX_DEFAULT_VALUE("winrt::PipsPagerButtonVisibility::Collapsed")] + PipsPagerButtonVisibility PreviousButtonVisibility; + [MUX_DEFAULT_VALUE("winrt::PipsPagerButtonVisibility::Collapsed")] + PipsPagerButtonVisibility NextButtonVisibility; + + Windows.UI.Xaml.Style PreviousButtonStyle; + Windows.UI.Xaml.Style NextButtonStyle; + + Windows.UI.Xaml.Style SelectedIndicatorButtonStyle; + Windows.UI.Xaml.Style DefaultIndicatorButtonStyle; + + event Windows.Foundation.TypedEventHandler SelectedIndexChanged; + + [MUX_PROPERTY_NEEDS_DP_FIELD] + PipsPagerTemplateSettings TemplateSettings{ get; }; + + static Windows.UI.Xaml.DependencyProperty NumberOfPagesProperty{ get; }; + static Windows.UI.Xaml.DependencyProperty SelectedPageIndexProperty{ get; }; + static Windows.UI.Xaml.DependencyProperty MaxVisualIndicatorsProperty{ get; }; + static Windows.UI.Xaml.DependencyProperty OrientationProperty{ get; }; + static Windows.UI.Xaml.DependencyProperty PreviousButtonVisibilityProperty{ get; }; + static Windows.UI.Xaml.DependencyProperty NextButtonVisibilityProperty{ get; }; + static Windows.UI.Xaml.DependencyProperty PreviousButtonStyleProperty{ get; }; + static Windows.UI.Xaml.DependencyProperty NextButtonStyleProperty{ get; }; + static Windows.UI.Xaml.DependencyProperty SelectedIndicatorButtonStyleProperty{ get; }; + static Windows.UI.Xaml.DependencyProperty DefaultIndicatorButtonStyleProperty{ get; }; +}; + +} diff --git a/dev/PipsPager/PipsPager.vcxitems b/dev/PipsPager/PipsPager.vcxitems new file mode 100755 index 0000000000..19738c4978 --- /dev/null +++ b/dev/PipsPager/PipsPager.vcxitems @@ -0,0 +1,47 @@ + + + + $(MSBuildAllProjects);$(MSBuildThisFileFullPath) + true + {D1EB61D8-C689-4AD1-BD61-FDAA50362563} + + + + %(AdditionalIncludeDirectories);$(MSBuildThisFileDirectory) + %(PreprocessorDefinitions);PipsPager_INCLUDED + + + + + + + + + + + + + + + + + + + + + RS1 + DefaultStyle + + + RS1 + ThemeResources + + + + + + + + + + \ No newline at end of file diff --git a/dev/PipsPager/PipsPager.xaml b/dev/PipsPager/PipsPager.xaml new file mode 100755 index 0000000000..1df9fd2bb8 --- /dev/null +++ b/dev/PipsPager/PipsPager.xaml @@ -0,0 +1,119 @@ + + + + + diff --git a/dev/PipsPager/PipsPagerAutomationPeer.cpp b/dev/PipsPager/PipsPagerAutomationPeer.cpp new file mode 100755 index 0000000000..a0bf413715 --- /dev/null +++ b/dev/PipsPager/PipsPagerAutomationPeer.cpp @@ -0,0 +1,83 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. See LICENSE in the project root for license information. + +#include "pch.h" +#include "common.h" +#include "ResourceAccessor.h" +#include "PipsPager.h" +#include "PipsPagerAutomationPeer.h" +#include "Utils.h" + +#include "PipsPagerAutomationPeer.properties.cpp" + +PipsPagerAutomationPeer::PipsPagerAutomationPeer(winrt::PipsPager const& owner) + : ReferenceTracker(owner) +{ +} + +// IAutomationPeerOverrides +winrt::IInspectable PipsPagerAutomationPeer::GetPatternCore(winrt::PatternInterface const& patternInterface) +{ + if (patternInterface == winrt::PatternInterface::Selection) + { + return *this; + } + + return __super::GetPatternCore(patternInterface); +} + +hstring PipsPagerAutomationPeer::GetClassNameCore() +{ + return winrt::hstring_name_of(); +} + +hstring PipsPagerAutomationPeer::GetNameCore() +{ + winrt::hstring name = __super::GetNameCore(); + + if (name.empty()) + { + if (const auto pipsPager = Owner().try_as()) + { + name = SharedHelpers::TryGetStringRepresentationFromObject(pipsPager.GetValue(winrt::AutomationProperties::NameProperty())); + } + } + + return name; +} + +winrt::AutomationControlType PipsPagerAutomationPeer::GetAutomationControlTypeCore() +{ + return winrt::AutomationControlType::Menu; +} + +com_ptr PipsPagerAutomationPeer::GetImpl() +{ + com_ptr impl = nullptr; + + if (const auto pipsPager = Owner().try_as()) + { + impl = winrt::get_self(pipsPager)->get_strong(); + } + + return impl; +} + +winrt::com_array PipsPagerAutomationPeer::GetSelection() +{ + if (const auto pager = GetImpl()) + { + return { winrt::box_value(pager->SelectedPageIndex()) }; + } + return {}; +} + +void PipsPagerAutomationPeer::RaiseSelectionChanged(double oldIndex, double newIndex) +{ + if (winrt::AutomationPeer::ListenerExists(winrt::AutomationEvents::PropertyChanged)) + { + RaisePropertyChangedEvent(winrt::SelectionPatternIdentifiers::SelectionProperty(), + winrt::PropertyValue::CreateDouble(oldIndex), + winrt::PropertyValue::CreateDouble(newIndex)); + } +} diff --git a/dev/PipsPager/PipsPagerAutomationPeer.h b/dev/PipsPager/PipsPagerAutomationPeer.h new file mode 100755 index 0000000000..f380ba0ab6 --- /dev/null +++ b/dev/PipsPager/PipsPagerAutomationPeer.h @@ -0,0 +1,32 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. See LICENSE in the project root for license information. + +#pragma once + +#include "PipsPager.h" +#include "PipsPagerAutomationPeer.g.h" + +class PipsPagerAutomationPeer : + public ReferenceTracker +{ + +public: + PipsPagerAutomationPeer(winrt::PipsPager const& owner); + + /* IAutomationPeerOverrides */ + winrt::IInspectable GetPatternCore(winrt::PatternInterface const& patternInterface); + hstring GetClassNameCore(); + hstring GetNameCore(); + winrt::AutomationControlType GetAutomationControlTypeCore(); + + // ISelectionProvider + bool CanSelectMultiple() { return false; }; + bool IsSelectionRequired() { return true; }; + winrt::com_array GetSelection(); + + void RaiseSelectionChanged(double oldIndex, double newIndex); + +private: + com_ptr GetImpl(); +}; + diff --git a/dev/PipsPager/PipsPagerAutomationPeer.idl b/dev/PipsPager/PipsPagerAutomationPeer.idl new file mode 100755 index 0000000000..ab91ce248a --- /dev/null +++ b/dev/PipsPager/PipsPagerAutomationPeer.idl @@ -0,0 +1,12 @@ +namespace MU_XAP_NAMESPACE +{ + +[WUXC_VERSION_PREVIEW] +[webhosthidden] +unsealed runtimeclass PipsPagerAutomationPeer : Windows.UI.Xaml.Automation.Peers.FrameworkElementAutomationPeer +{ + PipsPagerAutomationPeer(MU_XC_NAMESPACE.PipsPager owner); +} + +} + diff --git a/dev/PipsPager/PipsPagerSelectedIndexChangedEventArgs.h b/dev/PipsPager/PipsPagerSelectedIndexChangedEventArgs.h new file mode 100755 index 0000000000..89a9126b0c --- /dev/null +++ b/dev/PipsPager/PipsPagerSelectedIndexChangedEventArgs.h @@ -0,0 +1,21 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. See LICENSE in the project root for license information. + +#pragma once + +#include "PipsPagerSelectedIndexChangedEventArgs.g.h" + +class PipsPagerSelectedIndexChangedEventArgs : + public winrt::implementation::PipsPagerSelectedIndexChangedEventArgsT +{ +public: + PipsPagerSelectedIndexChangedEventArgs(const int previousIndex, const int newIndex) : + m_previousPageIndex(previousIndex), m_newPageIndex(newIndex) {}; + + int NewPageIndex() { return m_newPageIndex; }; + int PreviousPageIndex() { return m_previousPageIndex; }; + +private: + int m_newPageIndex = -1; + int m_previousPageIndex = -1; +}; diff --git a/dev/PipsPager/PipsPagerTemplateSettings.cpp b/dev/PipsPager/PipsPagerTemplateSettings.cpp new file mode 100755 index 0000000000..d5972b5754 --- /dev/null +++ b/dev/PipsPager/PipsPagerTemplateSettings.cpp @@ -0,0 +1,6 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. See LICENSE in the project root for license information. + +#include "pch.h" +#include "common.h" +#include "PipsPagerTemplateSettings.h" diff --git a/dev/PipsPager/PipsPagerTemplateSettings.h b/dev/PipsPager/PipsPagerTemplateSettings.h new file mode 100755 index 0000000000..51256a13f6 --- /dev/null +++ b/dev/PipsPager/PipsPagerTemplateSettings.h @@ -0,0 +1,16 @@ +#pragma once +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. See LICENSE in the project root for license information. + +#pragma once + +#include "PipsPagerTemplateSettings.g.h" +#include "PipsPagerTemplateSettings.properties.h" + +class PipsPagerTemplateSettings : + public winrt::implementation::PipsPagerTemplateSettingsT, + public PipsPagerTemplateSettingsProperties +{ +public: + PipsPagerTemplateSettings() { }; +}; diff --git a/dev/PipsPager/PipsPager_themeresources.xaml b/dev/PipsPager/PipsPager_themeresources.xaml new file mode 100755 index 0000000000..c8e6b2beb8 --- /dev/null +++ b/dev/PipsPager/PipsPager_themeresources.xaml @@ -0,0 +1,184 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 20 + 12 + + + + + + + + 20 + 20 + + 6 + + 5 + 3 + + + + + + + + + + + + + diff --git a/dev/PipsPager/Strings/en-us/Resources.resw b/dev/PipsPager/Strings/en-us/Resources.resw new file mode 100755 index 0000000000..585c3d9212 --- /dev/null +++ b/dev/PipsPager/Strings/en-us/Resources.resw @@ -0,0 +1,136 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + Pager + The name of the control itself that will be announced when it receives focus + + + Next Page + Automation name and tooltip text for the next page button + + + PreviousPage + Automation name and tooltip text for the previous page button + + + Page + Name used for UIA to announce controls, e.g. "Page 5" + + \ No newline at end of file diff --git a/dev/PipsPager/TestUI/PipsPagerPage.xaml b/dev/PipsPager/TestUI/PipsPagerPage.xaml new file mode 100755 index 0000000000..0cddd77e68 --- /dev/null +++ b/dev/PipsPager/TestUI/PipsPagerPage.xaml @@ -0,0 +1,108 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Visible + VisibleOnHover + Collapsed + + + Visible + VisibleOnHover + Collapsed + + + 0 Pages + 5 Pages + 10 Pages + 20 Pages + Inifinite NumberOfPages + + + 0 Pages + 1 Page + 5 Pages + 10 Pages + + + Vertical + Horizontal + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/dev/PipsPager/TestUI/PipsPagerPage.xaml.cs b/dev/PipsPager/TestUI/PipsPagerPage.xaml.cs new file mode 100755 index 0000000000..53c4df1f7c --- /dev/null +++ b/dev/PipsPager/TestUI/PipsPagerPage.xaml.cs @@ -0,0 +1,173 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. See LICENSE in the project root for license information. + +using System; +using Windows.UI.Xaml.Controls; +using System.Collections.Generic; +using System.Linq; +using PipsPagerButtonVisibility = Microsoft.UI.Xaml.Controls.PipsPagerButtonVisibility; +using PipsPagerSelectedIndexChangedEventArgs = Microsoft.UI.Xaml.Controls.PipsPagerSelectedIndexChangedEventArgs; +using Windows.UI.Xaml; +using Windows.UI.Xaml.Media; + +namespace MUXControlsTestApp +{ + [TopLevelTestPage(Name = "PipsPager")] + public sealed partial class PipsPagerPage : TestPage + { + Button previousPageButton; + Button nextPageButton; + + public List Pictures = new List() + { + + "Assets/ingredient1.png", + "Assets/ingredient2.png", + "Assets/ingredient3.png", + "Assets/ingredient4.png", + "Assets/ingredient5.png", + "Assets/ingredient6.png", + "Assets/ingredient7.png", + "Assets/ingredient8.png", + }; + + public PipsPagerPage() + { + this.InitializeComponent(); + this.Loaded += OnLoad; + } + + private void OnLoad(object sender, RoutedEventArgs args) + { + var rootPanel = VisualTreeHelper.GetChild(TestPipsPager, 0); + previousPageButton = VisualTreeHelper.GetChild(rootPanel, 0) as Button; + nextPageButton = VisualTreeHelper.GetChild(rootPanel, 2) as Button; + + PreviousPageButtonVisibilityComboBox.SelectionChanged += OnPreviousPageButtonVisibilityChanged; + NextPageButtonVisibilityComboBox.SelectionChanged += OnNextPageButtonVisibilityChanged; + TestPipsPagerNumberOfPagesComboBox.SelectionChanged += OnNumberOfPagesChanged; + TestPipsPagerMaxVisualIndicatorsComboBox.SelectionChanged += OnMaxVisualIndicatorsChanged; + TestPipsPagerOrientationComboBox.SelectionChanged += OnOrientationChanged; + TestPipsPager.PointerEntered += TestPipsPager_PointerEntered; + TestPipsPager.PointerExited += TestPipsPager_PointerExited; + previousPageButton.IsEnabledChanged += OnButtonEnabledChanged; ; + nextPageButton.IsEnabledChanged += OnButtonEnabledChanged; + + PreviousPageButtonIsVisibleCheckBox.IsChecked = IsButtonVisible(previousPageButton); + NextPageButtonIsVisibleCheckBox.IsChecked = IsButtonVisible(nextPageButton); + + PreviousPageButtonIsEnabledCheckBox.IsChecked = previousPageButton?.IsEnabled; + NextPageButtonIsEnabledCheckBox.IsChecked = nextPageButton?.IsEnabled; + + CurrentNumberOfPagesTextBlock.Text = GetNumberOfPages(); + CurrentMaxVisualIndicatorsTextBlock.Text = $"Current max visual indicators: {TestPipsPager.MaxVisualIndicators}"; + CurrentOrientationTextBlock.Text = GetCurrentOrientation(); + } + + private void OnButtonEnabledChanged(object sender, DependencyPropertyChangedEventArgs e) + { + if (sender == previousPageButton) + { + PreviousPageButtonIsEnabledCheckBox.IsChecked = previousPageButton?.IsEnabled; + } + else + { + NextPageButtonIsEnabledCheckBox.IsChecked = nextPageButton?.IsEnabled; + } + } + + private string GetCurrentOrientation() + { + return $"Current orientation is: {TestPipsPager.Orientation}"; + } + + private string GetNumberOfPages() + { + string prefix = "Current number of pages: "; + int numberOfPages = TestPipsPager.NumberOfPages; + return numberOfPages > 0 ? $"{prefix}{numberOfPages}" : $"{prefix}Inifinite"; + } + private bool IsButtonVisible(Button btn) + { + return btn?.Visibility == Visibility.Visible && btn?.Opacity != 0; + } + + private void TestPipsPager_PointerExited(object sender, Windows.UI.Xaml.Input.PointerRoutedEventArgs e) + { + PreviousPageButtonIsVisibleCheckBox.IsChecked = IsButtonVisible(previousPageButton); + NextPageButtonIsVisibleCheckBox.IsChecked = IsButtonVisible(nextPageButton); + } + + private void TestPipsPager_PointerEntered(object sender, Windows.UI.Xaml.Input.PointerRoutedEventArgs e) + { + PreviousPageButtonIsVisibleCheckBox.IsChecked = IsButtonVisible(previousPageButton); + NextPageButtonIsVisibleCheckBox.IsChecked = IsButtonVisible(nextPageButton); + } + + public void OnPreviousPageButtonVisibilityChanged(object sender, SelectionChangedEventArgs e) + { + TestPipsPager.PreviousButtonVisibility = ConvertComboBoxItemToVisibilityEnum((sender as ComboBox).SelectedItem as ComboBoxItem, TestPipsPager.PreviousButtonVisibility); + PreviousPageButtonIsVisibleCheckBox.IsChecked = IsButtonVisible(previousPageButton); + } + public void OnNextPageButtonVisibilityChanged(object sender, SelectionChangedEventArgs e) + { + TestPipsPager.NextButtonVisibility = ConvertComboBoxItemToVisibilityEnum((sender as ComboBox).SelectedItem as ComboBoxItem, TestPipsPager.NextButtonVisibility); + NextPageButtonIsVisibleCheckBox.IsChecked = IsButtonVisible(nextPageButton); + } + public void OnNumberOfPagesChanged(object sender, SelectionChangedEventArgs e) + { + TestPipsPager.NumberOfPages = ConvertComboBoxItemToNumberOfPages((sender as ComboBox).SelectedItem as ComboBoxItem); + CurrentNumberOfPagesTextBlock.Text = GetNumberOfPages(); + } + public void OnMaxVisualIndicatorsChanged(object sender, SelectionChangedEventArgs e) + { + TestPipsPager.MaxVisualIndicators = ConvertComboBoxItemToNumberOfPages((sender as ComboBox).SelectedItem as ComboBoxItem); + CurrentMaxVisualIndicatorsTextBlock.Text = $"Current max visual indicators: {TestPipsPager.MaxVisualIndicators}"; + } + + public void OnSelectedIndexChanged(object sender, PipsPagerSelectedIndexChangedEventArgs args) + { + PreviousPageButtonIsVisibleCheckBox.IsChecked = IsButtonVisible(previousPageButton); + NextPageButtonIsVisibleCheckBox.IsChecked = IsButtonVisible(nextPageButton); + + PreviousPageButtonIsEnabledCheckBox.IsChecked = previousPageButton?.IsEnabled; + NextPageButtonIsEnabledCheckBox.IsChecked = nextPageButton?.IsEnabled; + + CurrentPageIndexTextBlock.Text = $"Current index is: {args.NewPageIndex}"; + } + + public void OnOrientationChanged(object sender, SelectionChangedEventArgs e) + { + Orientation orientation = TestPipsPager.Orientation; + string selectedItem = ((sender as ComboBox).SelectedItem as ComboBoxItem).Content as string; + if (!Enum.TryParse(selectedItem, out orientation)) + { + System.Diagnostics.Debug.WriteLine("Unable to convert " + selectedItem + " to Orientation Enum"); + } + TestPipsPager.Orientation = orientation; + CurrentOrientationTextBlock.Text = GetCurrentOrientation(); + } + + private PipsPagerButtonVisibility ConvertComboBoxItemToVisibilityEnum(ComboBoxItem item, PipsPagerButtonVisibility defaultValue) + { + PipsPagerButtonVisibility newVisibility = defaultValue; + string selectedItem = item.Content as string; + if (!Enum.TryParse(selectedItem, out newVisibility)) + { + System.Diagnostics.Debug.WriteLine("Unable to convert " + selectedItem + " to PipsPagerButtonVisibility Enum"); + } + + return newVisibility; + } + private int ConvertComboBoxItemToNumberOfPages(ComboBoxItem item) + { + int numberOfPages = -1; + string digitsOnlyString = new String((item.Content as string).Where(Char.IsDigit).ToArray()); + if (!string.IsNullOrEmpty(digitsOnlyString)) + { + Int32.TryParse(digitsOnlyString, out numberOfPages); + } + return numberOfPages; + } + } +} diff --git a/dev/PipsPager/TestUI/PipsPager_TestUI.projitems b/dev/PipsPager/TestUI/PipsPager_TestUI.projitems new file mode 100644 index 0000000000..2c78e7c33f --- /dev/null +++ b/dev/PipsPager/TestUI/PipsPager_TestUI.projitems @@ -0,0 +1,23 @@ + + + + + $(MSBuildAllProjects);$(MSBuildThisFileFullPath) + true + 280C91F4-96B5-4BDE-9E02-E573E1DEF583 + + + PipsPager_TestUI + + + + Designer + MSBuild:Compile + + + + + PipsPagerPage.xaml + + + diff --git a/dev/PipsPager/TestUI/PipsPager_TestUI.shproj b/dev/PipsPager/TestUI/PipsPager_TestUI.shproj new file mode 100755 index 0000000000..49470981bb --- /dev/null +++ b/dev/PipsPager/TestUI/PipsPager_TestUI.shproj @@ -0,0 +1,14 @@ + + + + + {44F0E6BC-6222-4F16-8050-BB31DD804C4A} + 15.0 + + + + + + + + \ No newline at end of file diff --git a/dev/ResourceHelper/ResourceAccessor.h b/dev/ResourceHelper/ResourceAccessor.h old mode 100644 new mode 100755 index 2db626f4fc..c2e84c9ffd --- a/dev/ResourceHelper/ResourceAccessor.h +++ b/dev/ResourceHelper/ResourceAccessor.h @@ -118,6 +118,10 @@ class ResourceAccessor sealed #define SR_PagerControlPreviousPageButtonTextName L"PagerControlPreviousPageButtonText" #define SR_PagerControlNextPageButtonTextName L"PagerControlNextPageButtonText" #define SR_PagerControlLastPageButtonTextName L"PagerControlLastPageButtonText" +#define SR_PipsPagerNameText L"PipsPagerNameText" +#define SR_PipsPagerNextPageButtonText L"PipsPagerNextPageButtonText" +#define SR_PipsPagerPreviousPageButtonText L"PipsPagerPreviousPageButtonText" +#define SR_PipsPagerPageText L"PipsPagerPageText" #define SR_PlaceAfterString L"PlaceAfterString" #define SR_PlaceBeforeString L"PlaceBeforeString" #define SR_PlaceBetweenString L"PlaceBetweenString" diff --git a/dev/Telemetry/RuntimeProfiler.h b/dev/Telemetry/RuntimeProfiler.h index 70d3ad2c28..6a126da26c 100644 --- a/dev/Telemetry/RuntimeProfiler.h +++ b/dev/Telemetry/RuntimeProfiler.h @@ -50,6 +50,7 @@ namespace RuntimeProfiler ProfId_InfoBar, ProfId_Expander, ProfId_PagerControl, + ProfId_PipsPager, ProfId_ImageIcon, ProfId_Size // ProfId_Size is the last always. } ProfilerClassId; diff --git a/dev/dll/Microsoft.UI.Xaml.vcxproj b/dev/dll/Microsoft.UI.Xaml.vcxproj old mode 100644 new mode 100755 index cbe00d9ab7..9674bf81ec --- a/dev/dll/Microsoft.UI.Xaml.vcxproj +++ b/dev/dll/Microsoft.UI.Xaml.vcxproj @@ -141,6 +141,7 @@ + diff --git a/dev/dll/SharedHelpers.cpp b/dev/dll/SharedHelpers.cpp old mode 100644 new mode 100755 index 012ff859db..d571e7076a --- a/dev/dll/SharedHelpers.cpp +++ b/dev/dll/SharedHelpers.cpp @@ -138,6 +138,14 @@ bool SharedHelpers::IsScrollContentPresenterSizesContentToTemplatedParentAvailab return s_isScrollContentPresenterSizesContentToTemplatedParentAvailable; } +bool SharedHelpers::IsBringIntoViewOptionsVerticalAlignmentRatioAvailable() +{ + static bool s_isBringIntoViewOptionsVerticalAlignmentRatioAvailable = + IsRS4OrHigher() || + winrt::ApiInformation::IsPropertyPresent(L"Windows.UI.Xaml.BringIntoViewOptions", L"VerticalAlignmentRatio"); + return s_isBringIntoViewOptionsVerticalAlignmentRatioAvailable; +} + bool SharedHelpers::IsFrameworkElementInvalidateViewportAvailable() { static bool s_isFrameworkElementInvalidateViewportAvailable = IsRS5OrHigher(); @@ -565,6 +573,7 @@ winrt::IconElement SharedHelpers::MakeIconElementFrom(winrt::IconSource const& i } return bitmapIcon; } +#ifdef IMAGEICON_INCLUDED else if (auto imageIconSource = iconSource.try_as()) { winrt::ImageIcon imageIcon; @@ -578,6 +587,7 @@ winrt::IconElement SharedHelpers::MakeIconElementFrom(winrt::IconSource const& i } return imageIcon; } +#endif else if (auto pathIconSource = iconSource.try_as()) { winrt::PathIcon pathIcon; diff --git a/dev/inc/SharedHelpers.h b/dev/inc/SharedHelpers.h old mode 100644 new mode 100755 index b6f670f855..b595464381 --- a/dev/inc/SharedHelpers.h +++ b/dev/inc/SharedHelpers.h @@ -40,6 +40,8 @@ class SharedHelpers static bool IsScrollContentPresenterSizesContentToTemplatedParentAvailable(); + static bool IsBringIntoViewOptionsVerticalAlignmentRatioAvailable(); + static bool IsFrameworkElementInvalidateViewportAvailable(); static bool IsControlCornerRadiusAvailable(); diff --git a/test/IXMPTestApp/TAEF/IXMPTestApp.TAEF.csproj b/test/IXMPTestApp/TAEF/IXMPTestApp.TAEF.csproj old mode 100644 new mode 100755 diff --git a/test/MUXControls.Test/MUXControls.Test.Shared.targets b/test/MUXControls.Test/MUXControls.Test.Shared.targets old mode 100644 new mode 100755 index 33ce6c21e0..6ad05562cb --- a/test/MUXControls.Test/MUXControls.Test.Shared.targets +++ b/test/MUXControls.Test/MUXControls.Test.Shared.targets @@ -41,5 +41,6 @@ + \ No newline at end of file diff --git a/test/MUXControlsTestApp/MUXControlsTestApp.Shared.targets b/test/MUXControlsTestApp/MUXControlsTestApp.Shared.targets old mode 100644 new mode 100755 index 328212188c..8318ffd5d0 --- a/test/MUXControlsTestApp/MUXControlsTestApp.Shared.targets +++ b/test/MUXControlsTestApp/MUXControlsTestApp.Shared.targets @@ -89,6 +89,8 @@ + + \ No newline at end of file diff --git a/test/MUXControlsTestApp/TAEF/MUXControlsTestApp.TAEF.csproj b/test/MUXControlsTestApp/TAEF/MUXControlsTestApp.TAEF.csproj old mode 100644 new mode 100755