Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Add transform flip #116705

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 8 commits into from
Jan 21, 2023
Merged

Add transform flip #116705

merged 8 commits into from
Jan 21, 2023

Conversation

saminarp
Copy link
Contributor

@saminarp saminarp commented Dec 8, 2022

Adds Transform.flip to allow flipping/mirroring child widgets

Fixes #116702

Pre-launch Checklist

  • I read the Contributor Guide and followed the process outlined there for submitting PRs.
  • I read the Tree Hygiene wiki page, which explains my responsibilities.
  • I read and followed the Flutter Style Guide, including Features we expect every widget to implement.
  • I signed the CLA.
  • I listed at least one issue that this PR fixes in the description above.
  • I updated/added relevant documentation (doc comments with ///).
  • I added new tests to check the change I am making, or this PR is test-exempt.
  • All existing and new tests are passing.

@flutter-dashboard flutter-dashboard bot added the framework flutter/packages/flutter repository. See also f: labels. label Dec 8, 2022
@HansMuller HansMuller requested a review from justinmc December 9, 2022 22:25
@kevmoo
Copy link
Contributor

kevmoo commented Dec 9, 2022

Great first PR, @saminarp!! 👏 👏 👏

Copy link
Contributor

@justinmc justinmc left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just some nits and questions/discussions here before I approve.

I think I'm on board with adding this constructor, it makes sense to me to have a simple way to do this.

this.transformHitTests = true,
this.filterQuality,
super.child,
}) : transform = Matrix4.diagonal3Values(flipX ? -1.0 : 1.0, flipY ? -1.0 : 1.0, flipX ^ flipY ? -1.0 : 1.0);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think my gut says this is ok as-is, but I think we should discuss: What if we added an assert enforcing that flipX and flipY can't both be false?

On one hand it's somewhat confusing to have a widget called Transform.flip that doesn't flip anything. Users may try it without knowing about flipX/flipY and be confused that nothing flips.

On the other hand, it may be convenient to be able to use a Transform.flip that flips based on some state without having to exclude it from the widget tree.

What do you think?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We could use a List and fill it with the axes needed, empty list would mean no flip, but there would need to be a list and we could assert that

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Rereading this now, I think the best option is probably to keep it as-is.

I think a list is going to have the same problem by defaulting to an empty list plus more possibilities for invalid configuration.

We could default flipX and flipY to true, but I think it's okay to trust the user here and default them to false.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I agree: I don't think we should assert here, precisely because it might be used in a situation where two variables are both false, and the suggestion to use a List would make it more complicated than it needs to be.

Comment on lines +1448 to +1449
bool flipX = false,
bool flipY = false,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Another thing to think about: Is there a better way to represent this? For example, an enum with values like x, y, both, and none. Kind of similar to Axis.

I'm not saying that flipX/flipY aren't the best way to do this already, just starting a discussion again.

Copy link
Contributor

@gspencergoog gspencergoog Jan 6, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think two bools here is probably fine, given that it's a specialized constructor already. I can't think of any other ways that "flip" might be interpreted here, unless we also want to incorporate 90 degree rotations (which I don't think we do), and making it an enum makes it harder to write a call to the constructor using a boolean (which is probably the main use case here).


await tester.tapAt(topRight);

expect(tappedRed, true, reason: 'Transform.flip cannot flipX');
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

"true" => "isTrue"

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I have just done this in my recent commit

this.transformHitTests = true,
this.filterQuality,
super.child,
}) : transform = Matrix4.diagonal3Values(flipX ? -1.0 : 1.0, flipY ? -1.0 : 1.0, flipX ^ flipY ? -1.0 : 1.0);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What effect does the -1 z value have?

Copy link
Contributor Author

@saminarp saminarp Dec 10, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I applied matrix rotation and got this. So I thought I should preserve the value. It does not, however, affect the appearance as far as I noticed
9cfffd05-c8a8-49a1-9b1f-4e2740e2a200

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah I see, ok let's keep it 👍

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You shouldn't need to supply -1 in Z, you're just doing a 2D flip. I'd just always set it to 1.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Making Z constant to reduce unnecessary computation 👍

@@ -786,6 +786,101 @@ void main() {

expect(tester.getBottomRight(find.byType(Container)), target.bottomRight(tester.getTopLeft(find.byType(Container))));
});

testWidgets(
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nit: I would usually turn this test into a group and then turn each pumpWidget below into a separate test. That way you give each feature tested a chance to fail during one run and give a bit more info. Up to you if you think it's useful or not here, though.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just bumping this to make sure you saw it, though it's fine if you want to keep it as-is.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Let's keep it as-is.


expect(
tappedRed,
true,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nit: One small thing that might make this test somewhat fragile is that we're always expecting tappedRed to be true, so this test would pass for a big gesture detector that didn't flip at all. It would be more reassuring if you could test that the tap did not cause tappedRed to become true when nothing is flipped. Maybe do something like test that tapping topRight, bottomLeft, and bottomRight don't set tappedRed to true when there is no flip?

Up to you though, maybe it's not worth it to add that complexity.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I am a little behind schedule in a few of my college assignments. So, in my opinion, it is not worth adding the complexity at this time.

Let me know your thoughts :)

@saminarp
Copy link
Contributor Author

Great first PR, @saminarp!! 👏 👏 👏

Thank you so much!

@flutter-dashboard
Copy link

This pull request executed golden file tests, but it has not been updated in a while (20+ days). Test results from Gold expire after as many days, so this pull request will need to be updated with a fresh commit in order to get results from Gold.

For more guidance, visit Writing a golden file test for package:flutter.

Reviewers: Read the Tree Hygiene page and make sure this patch meets those guidelines before LGTMing.

@goderbauer goderbauer requested a review from justinmc January 3, 2023 23:15
Copy link
Contributor

@justinmc justinmc left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM 👍 assuming that the tests pass.

I restarted a few that were canceled, but it seems like you'll need to push a new commit to get the gold tests to re-run. Can you push a merge commit?

CC @gspencergoog for secondary review

this.transformHitTests = true,
this.filterQuality,
super.child,
}) : transform = Matrix4.diagonal3Values(flipX ? -1.0 : 1.0, flipY ? -1.0 : 1.0, flipX ^ flipY ? -1.0 : 1.0);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Rereading this now, I think the best option is probably to keep it as-is.

I think a list is going to have the same problem by defaulting to an empty list plus more possibilities for invalid configuration.

We could default flipX and flipY to true, but I think it's okay to trust the user here and default them to false.

this.transformHitTests = true,
this.filterQuality,
super.child,
}) : transform = Matrix4.diagonal3Values(flipX ? -1.0 : 1.0, flipY ? -1.0 : 1.0, flipX ^ flipY ? -1.0 : 1.0);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah I see, ok let's keep it 👍

@@ -786,6 +786,101 @@ void main() {

expect(tester.getBottomRight(find.byType(Container)), target.bottomRight(tester.getTopLeft(find.byType(Container))));
});

testWidgets(
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just bumping this to make sure you saw it, though it's fine if you want to keep it as-is.

Comment on lines +1448 to +1449
bool flipX = false,
bool flipY = false,
Copy link
Contributor

@gspencergoog gspencergoog Jan 6, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think two bools here is probably fine, given that it's a specialized constructor already. I can't think of any other ways that "flip" might be interpreted here, unless we also want to incorporate 90 degree rotations (which I don't think we do), and making it an enum makes it harder to write a call to the constructor using a boolean (which is probably the main use case here).

///
/// If `flipY` is true, the child widget will be flipped vertically. Defaults to false.
///
/// If both are true, the child widget will be flipped both vertically and horizontally.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You might mention that flipping it in both is equivalent to a 180 degree rotation.

/// If both are true, the child widget will be flipped both vertically and horizontally.
///
/// The [alignment] controls the origin of the flip; by default, this is
/// the center of the box.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What happens if the alignment is Alignment.upperLeft and both are flipped? Does it just draw nothing? Or does it draw outside of its bounding box?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actually, the more I think about it, isn't any alignment other than center going to draw nothing, or draw outside of its bounding box as long as one flip is true? That seems undesirable, since both are surprising.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It draws outside the bounding box if alignment is something other than center. Being restrictive, we could just fix the alignment to Alignment.center and not provide the option to change it at all. But allowing it may help someone desiring the undesirable results. But they could also do it using the main Transform() constructor. But again, the purpose of this flip constructor is to just simplify and be descriptive of what is being done. What do you prefer?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In that case, I think I'd prefer if we just eliminate the alignment argument altogether and just fix it at Alignment.center. It's surprising to have it draw outside of its bounding box, and if they want to do that, they can do it using the main constructor. We can always add it later if a compelling use case arises.

@nayeemtby nayeemtby force-pushed the add-transform-flip branch 2 times, most recently from 5795ac7 to 20eee94 Compare January 19, 2023 14:42
Copy link
Contributor

@gspencergoog gspencergoog left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

32384589-a60f0e74-c078-11e7-9bc1-e5b5287aea9d

Looks good, thanks for putting up with all of our comments. :-)

@gspencergoog gspencergoog added the autosubmit Merge PR when tree becomes green via auto submit App label Jan 19, 2023
@auto-submit auto-submit bot removed the autosubmit Merge PR when tree becomes green via auto submit App label Jan 19, 2023
@auto-submit
Copy link
Contributor

auto-submit bot commented Jan 19, 2023

auto label is removed for flutter/flutter, pr: 116705, due to - The status or check suite Windows build_tests_3_3 has failed. Please fix the issues identified (or deflake) before re-applying this label.

@nayeemtby
Copy link
Contributor

@gspencergoog Can you add the label again? It was removed and now all is green.

@kevmoo kevmoo added the autosubmit Merge PR when tree becomes green via auto submit App label Jan 21, 2023
@auto-submit auto-submit bot merged commit 8065887 into flutter:master Jan 21, 2023
engine-flutter-autoroll added a commit to engine-flutter-autoroll/packages that referenced this pull request Jan 22, 2023
engine-flutter-autoroll added a commit to engine-flutter-autoroll/plugins that referenced this pull request Jan 22, 2023
auto-submit bot pushed a commit to flutter/packages that referenced this pull request Jan 22, 2023
* 8065887 Add transform flip (flutter/flutter#116705)

* 68b6e72 406dce64f Roll Fuchsia Mac SDK from ZTKDeVL1HDAwsZdhl... to l7jVM3Urw73TVWfee... (flutter/engine#39050) (flutter/flutter#118964)

* cf628ad aa194347a Roll Fuchsia Linux SDK from S6wQW1tLFe-YnReaZ... to l3c_b-vRr-o6ZFX_M... (flutter/engine#39055) (flutter/flutter#118968)

* f33e8d3 2a2dfaafb Roll Fuchsia Mac SDK from l7jVM3Urw73TVWfee... to 5TQ9IL4-Yu3KHCR-H... (flutter/engine#39056) (flutter/flutter#118969)
engine-flutter-autoroll added a commit to engine-flutter-autoroll/plugins that referenced this pull request Jan 22, 2023
auto-submit bot pushed a commit to flutter/plugins that referenced this pull request Jan 22, 2023
* 3c769ef Cupertino navbar ellipsis fix (flutter/flutter#118841)

* d1be731 3fead63ba Roll Dart SDK from ac4c63168ff2 to 03d35455a8d8 (1 revision) (flutter/engine#39036) (flutter/flutter#118909)

* c0ad6ad Marks Mac plugin_test_macos to be unflaky (flutter/flutter#118706)

* 8372001 Remove unnecessary null checks in flutter_test (flutter/flutter#118865)

* 288a773 Remove unnecessary null checks in flutter_driver (flutter/flutter#118864)

* bb73121 Remove unnecessary null checks in flutter/test (flutter/flutter#118905)

* 15bc4e4 Marks Mac_android microbenchmarks to be flaky (flutter/flutter#118693)

* 1cdaf9e e2c2e5009 [impeller] correct input order in ColorFilterContents::MakeBlend (flutter/engine#39038) (flutter/flutter#118913)

* 49e025d Update android defines test to use emulator (flutter/flutter#118808)

* bae4c1d Revert "Update android defines test to use emulator (#118808)" (flutter/flutter#118928)

* 9837eb6 Remove unnecessary null checks in flutter/rendering (flutter/flutter#118923)

* 25843bd Remove macOS impeller benchmarks (flutter/flutter#118917)

* 70cecf6 Remove unnecessary null checks in dev/*_tests (flutter/flutter#118844)

* c757df3 Remove unnecessary null checks in dev/bots (flutter/flutter#118846)

* 5d74b5c Remove unnecessary null checks in flutter/painting (flutter/flutter#118925)

* 7272c80 Remove unnecessary null checks in `flutter/{animation,semantics,scheduler}` (flutter/flutter#118922)

* 2baea2f 7b68d71b8 Roll Dart SDK from 03d35455a8d8 to 807077cc5d1b (1 revision) (flutter/engine#39042) (flutter/flutter#118933)

* 8d60a8c Roll Flutter Engine from 7b68d71b8d03 to 3a444b36657c (3 revisions) (flutter/flutter#118938)

* 5ccdb81 bb4e8dfe2 Roll Fuchsia Linux SDK from rPo4_TYHCtkoOfRup... to S6wQW1tLFe-YnReaZ... (flutter/engine#39048) (flutter/flutter#118942)

* b1f4070 ef7b1856a Roll Dart SDK from 8c2eb20b5376 to 548678dd684c (1 revision) (flutter/engine#39049) (flutter/flutter#118944)

* 8065887 Add transform flip (flutter/flutter#116705)

* 68b6e72 406dce64f Roll Fuchsia Mac SDK from ZTKDeVL1HDAwsZdhl... to l7jVM3Urw73TVWfee... (flutter/engine#39050) (flutter/flutter#118964)

* cf628ad aa194347a Roll Fuchsia Linux SDK from S6wQW1tLFe-YnReaZ... to l3c_b-vRr-o6ZFX_M... (flutter/engine#39055) (flutter/flutter#118968)

* f33e8d3 2a2dfaafb Roll Fuchsia Mac SDK from l7jVM3Urw73TVWfee... to 5TQ9IL4-Yu3KHCR-H... (flutter/engine#39056) (flutter/flutter#118969)
mauricioluz pushed a commit to mauricioluz/plugins that referenced this pull request Jan 26, 2023
* 3c769ef Cupertino navbar ellipsis fix (flutter/flutter#118841)

* d1be731 3fead63ba Roll Dart SDK from ac4c63168ff2 to 03d35455a8d8 (1 revision) (flutter/engine#39036) (flutter/flutter#118909)

* c0ad6ad Marks Mac plugin_test_macos to be unflaky (flutter/flutter#118706)

* 8372001 Remove unnecessary null checks in flutter_test (flutter/flutter#118865)

* 288a773 Remove unnecessary null checks in flutter_driver (flutter/flutter#118864)

* bb73121 Remove unnecessary null checks in flutter/test (flutter/flutter#118905)

* 15bc4e4 Marks Mac_android microbenchmarks to be flaky (flutter/flutter#118693)

* 1cdaf9e e2c2e5009 [impeller] correct input order in ColorFilterContents::MakeBlend (flutter/engine#39038) (flutter/flutter#118913)

* 49e025d Update android defines test to use emulator (flutter/flutter#118808)

* bae4c1d Revert "Update android defines test to use emulator (#118808)" (flutter/flutter#118928)

* 9837eb6 Remove unnecessary null checks in flutter/rendering (flutter/flutter#118923)

* 25843bd Remove macOS impeller benchmarks (flutter/flutter#118917)

* 70cecf6 Remove unnecessary null checks in dev/*_tests (flutter/flutter#118844)

* c757df3 Remove unnecessary null checks in dev/bots (flutter/flutter#118846)

* 5d74b5c Remove unnecessary null checks in flutter/painting (flutter/flutter#118925)

* 7272c80 Remove unnecessary null checks in `flutter/{animation,semantics,scheduler}` (flutter/flutter#118922)

* 2baea2f 7b68d71b8 Roll Dart SDK from 03d35455a8d8 to 807077cc5d1b (1 revision) (flutter/engine#39042) (flutter/flutter#118933)

* 8d60a8c Roll Flutter Engine from 7b68d71b8d03 to 3a444b36657c (3 revisions) (flutter/flutter#118938)

* 5ccdb81 bb4e8dfe2 Roll Fuchsia Linux SDK from rPo4_TYHCtkoOfRup... to S6wQW1tLFe-YnReaZ... (flutter/engine#39048) (flutter/flutter#118942)

* b1f4070 ef7b1856a Roll Dart SDK from 8c2eb20b5376 to 548678dd684c (1 revision) (flutter/engine#39049) (flutter/flutter#118944)

* 8065887 Add transform flip (flutter/flutter#116705)

* 68b6e72 406dce64f Roll Fuchsia Mac SDK from ZTKDeVL1HDAwsZdhl... to l7jVM3Urw73TVWfee... (flutter/engine#39050) (flutter/flutter#118964)

* cf628ad aa194347a Roll Fuchsia Linux SDK from S6wQW1tLFe-YnReaZ... to l3c_b-vRr-o6ZFX_M... (flutter/engine#39055) (flutter/flutter#118968)

* f33e8d3 2a2dfaafb Roll Fuchsia Mac SDK from l7jVM3Urw73TVWfee... to 5TQ9IL4-Yu3KHCR-H... (flutter/engine#39056) (flutter/flutter#118969)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
autosubmit Merge PR when tree becomes green via auto submit App framework flutter/packages/flutter repository. See also f: labels.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Add a way to flip/mirror an widget
5 participants