Skip to content
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

Implement explicitly setting a center of rotation #783

Merged
merged 3 commits into from
Sep 3, 2024

Conversation

mario-kr
Copy link
Contributor

@mario-kr mario-kr commented May 25, 2023

Description

The transform-Widget provides "rotate" to rotate its child. However, the default center of rotation is (0, 0) (aka top-left), so it was not possible to, for example, rotate a child in-place.

This commit implements the additional options rotation-center-x and rotation-center-y. Both are optional, and the default value is 0.0 for each, so previous configurations should produce the same results.

Usage

(defwindow grid
  :stacking "fg"
  :windowtype "dock"
  :wm-ignore true
  :geometry (geometry
    :x "10px"
    :y "10px"
    :width "100px"
    :height "100px")
  (transform
    ;:rotate {-0.5 * percentloop}
    :rotate 15
    :transform-origin-x "50%"
    :transform-origin-y "50%"
    (box :orientation 'v' :style 'padding: 5px;'
      (box :orientation 'h'
        (label :style 'background-color: grey;' ' ')
        (label :style 'background-color: green;' ' '))
      (box :orientation 'h'
        (label :style 'background-color: red;' ' ')
        (transform
          :rotate {2*percentloop}
          :transform-origin-x "30%"
          :transform-origin-y "50%"
          :translate-x "-20%"
          (box
            (box :space-evenly true
              (label :style 'background-color: yellow;' ' ')
              (label :style 'background-color: black;' ' ')
              (label :style 'background-color: yellow;' ' '))))))))

(deflisten percentloop :initial 0 `i=0; while true; do let i=$i+1; echo $i; sleep .05; done`)
* {
    all: unset;
    margin: 0px;
    padding: 0px;
}

Showcase

I made a 5 second video of above configuration, but can't embed it here.

Additional Notes

  • There are artifacts, if, for example in the above configuration, the transform of the whole grid would be a static rotate. As this does not happen when everything is moving, maybe a redraw is missing somewhere.
  • The behaviour if both rotation-center-* and translate-* needs to be mentioned, though it is not "wrong". If an in-place/centered rotation is wanted, and a shift to the right, the shift to the right needs to be added on top of the rotation-center-value to get an in-place rotation.

Checklist

Please make sure you can check all the boxes that apply to this PR.

  • All widgets I've added are correctly documented.
  • I added my changes to CHANGELOG.md, if appropriate.
  • The documentation in the docs/content/main directory has been adjusted to reflect my changes.
  • I used cargo fmt to automatically format all code before committing

@elkowar
Copy link
Owner

elkowar commented Jun 8, 2023

  • I feel like we would want the origin to be relative to the position of the widget, such that you don't need to add the translation to the rotation-center value -- especially given that you'll most likely want to use percentages for the origin
  • I'd just call it transform-origin, keeping the consistency with how the same thing is called in CSS
  • I'm not sure if I correctly understand the kind of artifacts you're referring to -- I'll see if I can reproduce them, but obviously optimally, there wouldn't be any visual artifacts here 😉

@mario-kr
Copy link
Contributor Author

mario-kr commented Jul 8, 2023

Hi, sorry for the late response; I'll try to answer point by point:

  • If I understand correctly, then the translate-x/-y values should be added onto the origin, so that e.g. 50%/50% origin will always turn out to be an in-place rotation? As for units, the current implementation understands both percentages and pixels, so maximum flexibility for the user.
  • I renamed the variables to transform-origin. I am a bit unsure, if this is the same as in CSS, though that may be based on my inexperience with CSS in general.
  • IIRC I only changed the first :rotate value to 95 or something similar.

According to the documentation, the current transform-order is: rotate -> translate -> scale. But, looking at the code (https://github.com/elkowar/eww/blob/master/crates/eww/src/widgets/transform.rs#L165) it seems to be: scale -> rotate -> translate
Point 1 might affect this order too; scale after all changes the size of a widget, so any other transformation might possibly be affected. On the other hand, the current implementation retrieves the allocated_width/height exactly once, and uses that same value for all transformations, so the transformation might currently actually be independent of each other (somewhat)?

@mario-kr mario-kr force-pushed the configurable-rotation-center branch 3 times, most recently from fd4100b to ae5cb63 Compare June 4, 2024 09:56
@mario-kr
Copy link
Contributor Author

mario-kr commented Jun 4, 2024

Update:
I noticed #1103 when I looked at this project regarding the wrong EWW_NET values, and decided to renew this PR a bit.

  • rebased to master, fixed any hiccups due to a different way of defining properties since I last worked on this
  • updated the example rotation config

@mario-kr mario-kr force-pushed the configurable-rotation-center branch from ae5cb63 to 9e71cf3 Compare June 8, 2024 10:35
Copy link
Contributor

@w-lfchen w-lfchen left a comment

Choose a reason for hiding this comment

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

lgtm!
just one minor question, see the comment

cr.translate(transform_origin_x, transform_origin_y);
cr.rotate(perc_to_rad(rotate));
cr.translate(translate_x, translate_y);
cr.translate(translate_x - transform_origin_x, translate_y - transform_origin_y);
Copy link
Contributor

Choose a reason for hiding this comment

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

this doesn't break the order defined here, right?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Well, even before this patch, the methods called on cr are in the order:

  1. scale
  2. rotate
  3. translate

whereas in the comment you linked, it's claimed that the order is:

  1. rotate
  2. translate
  3. scale

Sooooo... I don't know? Was it ever in the right order? Or is it sorted by the cairo-Context?

Copy link
Contributor

Choose a reason for hiding this comment

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

it doesn't sort them, if i'm understanding the docs right.
i suggest sorting them in the order described in the documentation, though i don't think it makes much of a difference.

also, the only thing causing the merge conflict is the changelog entry, that should be trivial to resolve when rebasing onto master ^^

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Screenshot from 2024-08-29 17-46-53

There is a difference I'm afraid.
On the left side, scale is called after rotate + translate. basically, it warps the contents into a parallelogram when rotated. (the scaling is applied in the original directions of the x and y axis)
On the right is the same eww.yuck, but scale is called before rotate+translate, or the whole, scaled widget is rotated.

Generally speaking, users can always force a specific order by nesting multiple transforms. I did this here, where i nested the rotate+translate transform inside the scale transform:
Screenshot from 2024-08-29 18-00-03
but it's not entirely the same; the bottom seems to be cut off (Because the size on the y-axis for this widget was limited by the scale to 60%)

soo... do we want the warping rotate as the default (scale after rotate, as documented), or do we want the non-warping rotate as the default (as previously implemented)?

Copy link
Contributor

@w-lfchen w-lfchen Aug 29, 2024

Choose a reason for hiding this comment

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

i'm pretty sure non-warping rotation is a saner default, the documentation should be updated accordingly

@mario-kr mario-kr force-pushed the configurable-rotation-center branch from 9fc4393 to 4058a42 Compare August 29, 2024 17:15
Copy link
Contributor

@w-lfchen w-lfchen left a comment

Choose a reason for hiding this comment

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

thank you for your work <3

@mario-kr
Copy link
Contributor Author

please do not merge yet, I want to double-check it's correct

The transform-Widget provides "rotate" to rotate its child. However, the
default center of rotation is (0, 0) (aka top-left), so it was not
possible to, for example, rotate a child in-place.

This commit implements the additional options `transform-origin-x` and
`transform-origin-y`. Both are optional, and the default value is 0.0 for
each, so previous configurations should produce the same results.
@mario-kr mario-kr force-pushed the configurable-rotation-center branch from 4058a42 to d3113ff Compare August 29, 2024 17:42
@mario-kr
Copy link
Contributor Author

Ok, that was a bit close for comfort, but re-checking what I did was the right decision.

The non-warping version is the one with the previously documented method-order, rotate->translate->scale.

I have rebuild this newest force-pushed commit both with nix build and nix develop -> cargo build --bin eww, both times yielding the desired result of the contents not being warped.

Sry for the mix-up.

@w-lfchen
Copy link
Contributor

thank you for double-checking!

just as a heads-up: there should be no difference in how you build if you execute the commands the way you stated ^^

@elkowar elkowar merged commit 8661abf into elkowar:master Sep 3, 2024
1 check passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants