Skip to content

feat: Apply orientation to UI too, move setting to Display#499

Open
maeveynot wants to merge 1 commit intocrosspoint-reader:masterfrom
maeveynot:landscape-ui
Open

feat: Apply orientation to UI too, move setting to Display#499
maeveynot wants to merge 1 commit intocrosspoint-reader:masterfrom
maeveynot:landscape-ui

Conversation

@maeveynot
Copy link
Contributor

@maeveynot maeveynot commented Jan 22, 2026

Summary

As a landscape-orientation reader, I would prefer to not have to physically rotate my device to use some (but not all) other parts of the UI. This PR moves the orientation setting from the Reader category to the Device category, and applies orientation to all activities, not just the reader.

Rather than setting the orientation in the reader activity and setting it back, we change the orientation only:

  • At boot
  • When changing the setting (takes effect immediately)
  • Back to portrait when going to sleep, since all existing wallpaper is portrait and nobody wants to change that
  • Similarly, into portrait for reading XTCs, since those are all logically portrait (if they were generated as landscape, they're still 480x800 with the text sideways)

We introduce some code into the base Activity class to handle both this and the concept of "margins", which in many cases were kind of hard-coded into other activities with the assumption of portrait. With a place for some code there I then refactored menus a bit by collecting duplicated code for the calculation of number of menu items on screen. This work could be continued further to actually drawing the menu items, but I'm hoping for feedback first.

Finer-grained breakdown of changes:

  • Adjust the size of the button hints to better match the physical buttons. I came up with the new width by eyeballing it. Text still fits. This was needed because otherwise the buttons would overlap with the battery display in the home activity.
  • Move Activity's onEnter/onExit out of the .h file. While the renderer orientation only needs to be changed in the circumstances above, the margins are member variables of each activity instance, so they need to be initialized in onEnter based on the current orientation.
  • Take the CONTENT_START_Y and LINE_HEIGHT constants from the my-library activity and set them in Activity so that all menu-drawing activities can use them instead of literal 60 and 30. (also, instead of 60 it's now the top margin + 45.)
  • The book tile label is one case where we were centering things relative to the screen, but now we have to center them relative to the tile, since in landscape there is more margin on one side.
  • In the web server activity, a width of 480 was hardcoded; use the screen width instead so that the QR code is still centered in landscape.
  • In the wifi selection screen, the MAC address etc labels would run over the network names list as they were, so draw them right-aligned instead (adding some space on the right to not overlap any indicators).
  • In settings, draw the version number in the corner of the header instead of next to the button hints, because for landscape there are labels right next to the button hints.
  • Move all keyboard entry activity keyboards down to 50 pixels, like wifi password entry (centering would be nice, but I we don't know the height when calling the constructor). Previously this was inconsistent between wifi and OPDS/KOreader settings.

Visual problems that still exist at this point:

  • In the my-library activity, Landscape CCW, the button hints cover up the scroll indicator. I don't really need the scroll indicator, but maybe just not drawing it or moving the numbers to the corner would be preferable. Hoping for feedback.

Random other notes:

  • I initially prototyped this work off of 0.14, where all settings were still in one screen, so I had to adapt the settings activity to scroll between pages like other menus. With the settings split into categories, this is not currently an issue, but, more settings will be added in the future and landscape orientation will run out of space before portrait does, so at some point that should be revisited.

Additional Context

There may be unpolished spots here but since this will affect and conflict with other menu work (EDIT: there are now PRs: #528, #548) I want to get it up here and under discussion (and hopefully merged) as soon as possible, with improvements to follow.

I don't use every feature of CrossPoint, so I may have missed testing some things. I'm prioritizing attention to usability in Portrait and Landscape CCW orientations.

If we want to go in this direction, I would like to follow up with opening a discussion about remapping buttons in the new my-library activity, because I really strongly don't like the current ones. For me the outer side of the button should always be "next page or menu item" and the inner side of the button should always be "previous page or menu item" and now they switch between tabs and I have to use the side button to scroll. I am not changing this new behavior here since discussion of what mapping settings to add is needed.

AI Usage

No

@maeveynot maeveynot changed the title Apply orientation to UI too, move setting to Display feat: Apply orientation to UI too, move setting to Display Jan 22, 2026
@maeveynot maeveynot force-pushed the landscape-ui branch 12 times, most recently from c733abc to 0fc2ba0 Compare January 25, 2026 21:24
@maeveynot
Copy link
Contributor Author

maeveynot commented Jan 25, 2026

I removed the visual change where the continue-reading book tile expanded to fill available space, and kept it at half the screen size as before--we just limit the height if that's needed. By doing this we can eliminate another max height check later on.

I'm absolutely open to better dimension or a side-by-side cover and text continue-reading tile, but that can be decided later.

@maeveynot maeveynot force-pushed the landscape-ui branch 2 times, most recently from 1857a4f to da0f3f6 Compare January 25, 2026 21:39
@maeveynot
Copy link
Contributor Author

maeveynot commented Jan 26, 2026

I originally included some stuff about image orientation in the boot/sleep activity here, but I broke that out into #557 .

This branch is one commit on top of that PR's branch; the other PR should be merged first to get its own squash commit. I think this PR should squash fine after that but if needs to be rebased please feel free to do that.

If reviewing changes here before merging #557, you will see that branch included in the diff.

daveallie pushed a commit that referenced this pull request Jan 27, 2026
## Summary

This was originally a comment in #499, but I'm making it its own PR,
because it doesn't depend on anything there and then I can base that PR
on this one.

Currently, `drawBitmap` is used for covers and sleep wallpaper, and
`drawImage` is used for the boot logo. `drawBitmap` goes row by row and
pixel by pixel, so it respects the renderer orientation. `drawImage`
just calls the `EInkDisplay`'s `drawImage`, which works in the eink
panel's native display orientation.

`drawImage` rotates the x,y coordinates where it's going to draw the
image, but doesn't account for the fact that the northwest corner in
portrait orientation becomes, the southwest corner of the image
rectangle in the native orientation. The boot and sleep activities
currently work around this by calculating the north*east* corner of
where the image should go, which becomes the northwest corner after
`rotateCoordinates`.

I think this wasn't really apparent because the CrossPoint logo is
rotationally symmetrical. The `EInkDisplay` `drawImage` always draws the
image in native orientation, but that looks the same for the "X" image.

If we rotate the origin coordinate in `GfxRenderer`'s `drawImage`, we
can use a much clearer northwest corner coordinate in the boot and sleep
activities. (And then, in #499, we can actually rotate the boot screen
to the user's preferred orientation).

This does *not* yet rotate the actual bits in the image; it's still
displayed in native orientation. This doesn't affect the
rotationally-symmetric logo, but if it's ever changed, we will probably
want to allocate a new `u8int[]` and transpose rows and columns if
necessary.

## Additional Context

I've created an additional branch on top of this to demonstrate by
replacing the logo with a non-rotationally-symmetrical image:

<img width="128" height="128" alt="Cat-in-a-pan-128-bw"
src="https://github.com/user-attachments/assets/d0b239bc-fe75-4ec8-bc02-9cf9436ca65f"
/>


master...maeveynot:rotated-cat

(many thanks to https://notisrac.github.io/FileToCArray/)

As you can see, it is always drawn in native orientation, which makes it
sideways (turned clockwise) in portrait.

---

### AI Usage

No

Co-authored-by: Maeve Andrews <[email protected]>
@maeveynot maeveynot force-pushed the landscape-ui branch 2 times, most recently from 0948b8f to fdd4b0c Compare January 27, 2026 16:42
@maeveynot
Copy link
Contributor Author

Conflicts resolved and rebased on master. Thanks for merging #557!

@maeveynot maeveynot force-pushed the landscape-ui branch 4 times, most recently from 843f41c to 5234ff3 Compare January 27, 2026 21:52
@maeveynot
Copy link
Contributor Author

I have updated this to essentially undo #637 since we provide space here for the hints to be drawn. @daveallie could you let me know if it's worth continuing to do this or if you'd like to move in the direction of themeing systems instead? It seems like UI rotation will be a lot more complicated there since both the theme engine and the themes themselves would need to support it.

@CaptainFrito
Copy link
Contributor

Hi @maeveynot, I wrote the UI theme PR #528, I really dig the work you've done here to make the UI more "responsive". With the introduction of themes it will actually be easier to do this, since we're migrating to a components architecture rather than rendering hardcoded primitives on every screen. Every component is drawn using a Rect{x, y, w, h} frame parameter and layout constants are centralized in each theme. We could work together on implementing your changes into this system if you'd like.

Jessica765 pushed a commit to Jessica765/crosspoint-reader that referenced this pull request Feb 3, 2026
## Summary

This was originally a comment in crosspoint-reader#499, but I'm making it its own PR,
because it doesn't depend on anything there and then I can base that PR
on this one.

Currently, `drawBitmap` is used for covers and sleep wallpaper, and
`drawImage` is used for the boot logo. `drawBitmap` goes row by row and
pixel by pixel, so it respects the renderer orientation. `drawImage`
just calls the `EInkDisplay`'s `drawImage`, which works in the eink
panel's native display orientation.

`drawImage` rotates the x,y coordinates where it's going to draw the
image, but doesn't account for the fact that the northwest corner in
portrait orientation becomes, the southwest corner of the image
rectangle in the native orientation. The boot and sleep activities
currently work around this by calculating the north*east* corner of
where the image should go, which becomes the northwest corner after
`rotateCoordinates`.

I think this wasn't really apparent because the CrossPoint logo is
rotationally symmetrical. The `EInkDisplay` `drawImage` always draws the
image in native orientation, but that looks the same for the "X" image.

If we rotate the origin coordinate in `GfxRenderer`'s `drawImage`, we
can use a much clearer northwest corner coordinate in the boot and sleep
activities. (And then, in crosspoint-reader#499, we can actually rotate the boot screen
to the user's preferred orientation).

This does *not* yet rotate the actual bits in the image; it's still
displayed in native orientation. This doesn't affect the
rotationally-symmetric logo, but if it's ever changed, we will probably
want to allocate a new `u8int[]` and transpose rows and columns if
necessary.

## Additional Context

I've created an additional branch on top of this to demonstrate by
replacing the logo with a non-rotationally-symmetrical image:

<img width="128" height="128" alt="Cat-in-a-pan-128-bw"
src="https://github.com/user-attachments/assets/d0b239bc-fe75-4ec8-bc02-9cf9436ca65f"
/>


crosspoint-reader/crosspoint-reader@master...maeveynot:rotated-cat

(many thanks to https://notisrac.github.io/FileToCArray/)

As you can see, it is always drawn in native orientation, which makes it
sideways (turned clockwise) in portrait.

---

### AI Usage

No

Co-authored-by: Maeve Andrews <[email protected]>
@maeveynot
Copy link
Contributor Author

@CaptainFrito thanks! I'll take a look at what needs to be done or not now that #528 is merged, and see what I can reimplement... maybe this PR as is should be abandoned.

@CaptainFrito CaptainFrito mentioned this pull request Feb 10, 2026
Unintendedsideeffects pushed a commit to Unintendedsideeffects/crosspoint-reader that referenced this pull request Feb 17, 2026
## Summary

This was originally a comment in crosspoint-reader#499, but I'm making it its own PR,
because it doesn't depend on anything there and then I can base that PR
on this one.

Currently, `drawBitmap` is used for covers and sleep wallpaper, and
`drawImage` is used for the boot logo. `drawBitmap` goes row by row and
pixel by pixel, so it respects the renderer orientation. `drawImage`
just calls the `EInkDisplay`'s `drawImage`, which works in the eink
panel's native display orientation.

`drawImage` rotates the x,y coordinates where it's going to draw the
image, but doesn't account for the fact that the northwest corner in
portrait orientation becomes, the southwest corner of the image
rectangle in the native orientation. The boot and sleep activities
currently work around this by calculating the north*east* corner of
where the image should go, which becomes the northwest corner after
`rotateCoordinates`.

I think this wasn't really apparent because the CrossPoint logo is
rotationally symmetrical. The `EInkDisplay` `drawImage` always draws the
image in native orientation, but that looks the same for the "X" image.

If we rotate the origin coordinate in `GfxRenderer`'s `drawImage`, we
can use a much clearer northwest corner coordinate in the boot and sleep
activities. (And then, in crosspoint-reader#499, we can actually rotate the boot screen
to the user's preferred orientation).

This does *not* yet rotate the actual bits in the image; it's still
displayed in native orientation. This doesn't affect the
rotationally-symmetric logo, but if it's ever changed, we will probably
want to allocate a new `u8int[]` and transpose rows and columns if
necessary.

## Additional Context

I've created an additional branch on top of this to demonstrate by
replacing the logo with a non-rotationally-symmetrical image:

<img width="128" height="128" alt="Cat-in-a-pan-128-bw"
src="https://github.com/user-attachments/assets/d0b239bc-fe75-4ec8-bc02-9cf9436ca65f"
/>


crosspoint-reader/crosspoint-reader@master...maeveynot:rotated-cat

(many thanks to https://notisrac.github.io/FileToCArray/)

As you can see, it is always drawn in native orientation, which makes it
sideways (turned clockwise) in portrait.

---

### AI Usage

No

Co-authored-by: Maeve Andrews <[email protected]>
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.

2 participants