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 DrawTarget for &mut T: DrawTarget #706
base: master
Are you sure you want to change the base?
Conversation
Just to mention that the CI fails as the code is of course not completely backwards compatible: display drivers that used to only implement |
Thanks for the PR. I had tried to implement this before and also encountered the problem with the |
Thanks for the feedback. Please let me know when/if you would need my assistance to upstream this PR. Might be useful to other folks who hit the same issue. As you can see, the code ain't pretty and even needs lifetime GATs, hence this PR. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Perhaps we should just get rid of the OriginDimensions
trait entirely. If I remember correctly, the only place where it is really required is the ImageDrawable
trait, but we could also add a size
method to ImageDrawable
.
where | ||
I: IntoIterator<Item = Pixel<Self::Color>>, | ||
{ | ||
(**self).draw_iter(pixels) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Just a stylistic choice, but IMO using the T
type explicitly makes these statements easier to understand:
(**self).draw_iter(pixels) | |
T::draw_iter(self, pixels) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't really have a strong preference here, so I'm fine with that.
@@ -95,7 +95,7 @@ mod tests { | |||
let mut display = MockDisplay::new(); | |||
|
|||
let area = Rectangle::new(Point::new(2, 1), Size::new(2, 4)); | |||
let mut clipped = display.clipped(&area); | |||
let mut clipped = (&mut display).clipped(&area); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Code like this will be probably be pretty common and I think we should make it a bit nicer:
let mut clipped = (&mut display).clipped(&area); | |
let mut clipped = display.by_ref().clipped(&area); |
This could be implemented by adding a by_ref
method to the DrawTarget
trait, like in the std::io::Read
trait https://doc.rust-lang.org/src/std/io/mod.rs.html#841-881.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ditto. Let me make those changes in the next days. Perhaps the key question is what we have to do w.r.t. Dimension
and OriginDimension
from above.
Wouldn't it be simpler if we actually do the reverse:
That means, we should retire the And yes, there are "odd" displays like a TTGO ESP32 board I've seen where the top-left corner is not (0, 0), but I would then say, this is the duty of the driver to do the necessary |
I'm not sure I want to loose the flexibility of allowing
Yes, this should be handled by the display driver. |
Strong argument, I agree. In any case, we are aligned on getting rid of either |
I think so. While I did liked the idea of having the type level guarantee that the top left corner of a draw target is at Another argument for keeping the |
Thanks for asking :). I agree with this - I think it's really useful to be able to massage the coordinate system. If we see a native UI library built on e-g at some point, one motivating use case for this feature is being able to take sub-regions of the display to lay out sub-pieces of the UI with minimal maths. I'd be ok seeing |
OK, great to see that we all seem to agree that just removing
Yes, I think this would help. Or we could use this: #448 (comment) |
Nice find from 2020! |
Thank you for helping out with embedded-graphics development! Please:
CHANGELOG.md
entry in the Unreleased section under the appropriate heading (Added, Fixed, etc) if your changes affect the public APIrustfmt
on the projectjust build
(Linux/macOS only) and make sure it passes. If you use Windows, check that CI passes once you've opened the PR.PR description
Is there any reason why
DrawTarget
is not implemented for&mut T where T: DrawTarget
?The major inconvenience of the above is that
Clipped
,Translated
,Cropped
and - overall - theDrawTargetExt
decorator decorates only&mut DrawTarget
references, and not genericDrawTarget
instances where these can be either moved or passed by a mutable reference.As a result, I cannot fulfill the simple use case of creating a display driver, then decorating it and finally moving it into a generic drawing code that needs to own the display. Passing the display to the drawing code by
&mut
reference is simply not an option for a variety of reasons.Here's a concrete use case:
Cropped
- as the display is weird and does not start at (0, 0), nor does it report correctDimensions
bounding boxColorConverted
so that my drawing code always use a fixed, customColor
color and is thus display color independentSure, implementing
&mut T where T: DrawTarget
also means implementing&mut T
and&T
forDimensions
andOriginDimensions
, but that's OK. What is not so ideal is that once these are implemented, the implementation ofDimensions
forT: OriginDimensions
conflicts and should be removed, but the question is what is the better compromise:DrawTarget
for&mut T
(similarly to the traits inembedded-hal
and theRead
/Write
traits in STD and allow the user to decorateDrawTarget
instances by move or by&mut
reference)Dimensions
is auto-implemented for types implementingOriginDimensions
, but thenDrawTarget
decoration capabilities of the library are severely limitedWith Option 1, there is the extra benefit, that
Drawable
no longer needs to take&mut DrawTarget
and can just switch to plainDrawTarget
.