How to use the mini screen core components?

I have been trying to figure out how to use the miniscreen core components. Things like the marquee text, page_menu, selectable_list, etc. But I have no clue how to use it and I can’t seem to find documentation on it.

I have tried creating an app before, however despite displaying the menu it was not being controlled properly by the pi-top’s hardware

Any help would be much appreciated!

Hi there,

That’s great that you are trying out the Miniscreen Core, we are hoping to get it into the SDK at some point in the future so I’m happy to hear you are looking at it! I should warn you that it is currently only intended for internal use so things might change without warning until it is in the SDK.

Having said that I’m happy to help if I can! It could be that the button handling needs to be tweaked, is it the buttons that aren’t working for you? I’ve updated the README to have a bit of a better explanation on how to do the button handling, you can find that here. If you have any more questions please feel free to open an issue on the repo and we’ll try to answer them there and improve the documentation :smile:

All the best,

Olivier

Hello! Thank you so much for helping. Currently this block of code is not working for me

class QueueActions(SelectableList):
    def __init__(self, song_title:str, **kwargs) -> None:
        super().__init__(
            Rows=[
                partial(ListItem, text=song_title),
                PlayNow,
                PlayNext,
                Remove
            ],
            num_visible_rows=5,
            **kwargs,
        )

class QueueRow(Component):
    def __init__(self, title: str, **kwargs) -> None:
        super().__init__(**kwargs)
        self.text = self.create_child(
            MarqueeText,
            text=title,
            font_size=10,
            align="center",
            vertical_align="center",
        )
        self.page = partial(
            QueueActions,
            song_title=title
        )

    def render(self, image):
        return self.text.render(image)

class Queue(SelectableList):
    def __init__(self, **kwargs) -> None:
        super().__init__(
            Rows=self.load_directory_rows(),
            num_visible_rows=5,
            **kwargs,
        )
    def load_directory_rows(self) -> List:
        rows: List[Union[Type[EmptyQueue], partial[QueueRow]]] = []
        queue = ["song1", "song2", "song3"]
        for title in queue:
            rows.append(
                    partial(
                        QueueRow, title=title
                    )
                )
        
        if len(rows) == 0:
            rows.append(partial(ListItem, text="Queue is empty"))

        return rows

I have a selectable list and each element leads to another selectable list. But for some reason the second selectable list is not really controllable. Only the x and o buttons works. The up and down arrows do not work at all

No worries at all! I suspect that you may be calling the select_next_row and select_previous_row methods on the top SelectableList but not the nested ones, that is just a guess however. Please can you share the class that calls those methods?

I am building another widget menu widget for PT_miniscreen, so App.py is the one that is calling the two functions:

    def handle_up_button_release(self):
        if self.root.is_project_page:
            return

        if self.root.can_select_row:
            self.root.select_previous_row()
        elif self.root.can_scroll:
            self.root.scroll_up()

    def handle_down_button_release(self):
        if self.root.is_project_page:
            return

        if self.root.can_select_row:
            self.root.select_next_row()
        elif self.root.can_scroll:
            self.root.scroll_down()

Makes sense to me, in our root component (self.root in App) we use a Stack component to render nested SelectableLists. The Stack component has an active_component property which is how we call methods on the SelectableList that is currently rendered, e.g. self.stack.active_component.select_next_row(). Are you doing a similar thing in your self.root component? Or is your root component one of the ones you’ve already mentioned above?

I am not currently doing that, thank you so much! I will see if I can do something similar

1 Like

Oh I should mention that I am making the app directly on the miniscreen app (probably not a good idea…), so I think I am using the stack that your app uses?

Oh I see! In that case it would be more complicated as we have a general solution to nested lists that you would need to hook into.

Instead I recommend starting with a clean App from core and copying some stuff from your existing App and Root. It will probably be easier since you don’t not need to have a general solution like we do. For example you can keep the information for which list you are looking at, the available songs, the song you are currently viewing and the queue all in the Root class. You probably don’t need a stack in that case as you can switch out which page you are showing based on the state. If you need to know which page to show based on which row is currently selected then you can get some identifying information from the row instance, for example self.current_list.selected_row.state["id"].

We also have a way to add your widget to the main Miniscreen app if you want to do that: you can add it to the Projects menu by putting your code into /home/pi/Desktop/Projects, for example /home/pi/Desktop/Projects/music-player. Then you need to add a project.cfg file in that directory, that is what we use to find information about the project such as it’s name and how to run it. The project.cfg file format looks like this:

[project]
title=Music Player
start=python3 -B start.py
exit_condition=HOLD_CANCEL

where start.py would be:

from signal import pause
from threading import Thread

# this might need to change depending on how you need to import App
from app import App

app = App()
Thread(target=app.start).start()
pause()

Having said that if you want to try to get it working with the existing code instead you’ll need to replace your SelectableList classes with EnterableSelectableList from pt_miniscreen/components/enterable_selectable_list, then your Rows need to inherit from Enterable which can be found in pt_miniscreen/components/mixins. Enterable is a mixin that we use to figure out what component to push to the stack when select is pressed. Your Row classes will need to add a enterable_component property similarly to how EnterableSelectableList does.

I hope that is helpful! Please let me know how you get on, it sounds like an interesting project!