Pegasus theme development general
-
Before you all start writing overly complex things, please note that theme-specific settings and an auto updater will come eventually to Pegasus :)
-
Oh for sure! I don't mind really, because it's getting me to learn QML/QT, it's a fun practice exercise, looking forward to the official implementation and removing my old one.
-
Some progress on my settings screen.
-
@fluffypillow I'm trying to use the api.memory.get() and api.memory.set() but it does not seem to be doing anything. Here's the code I'm trying (in theme.qml), and then I go look at
~/.config/pegasus-frontend/theme_settings/gameOS.json
and it never updates, none of my stored values appear in there. Not sure what I'm doing wrong. Maybe I can only pass it actual variables and not values? Nope, that didn't make any difference either. I tried renaming gameOS.json expecting for it to be replaced on the next api.memory.set() but it did not. Really can't figure this out. OKAY! Haha I figured something out I think. It seemed to only work when I switched the theme away from gameOS and back to gameOS. After more testing of it, looks like it does not store the setting from api.memory.set() unless and until you switch theme's away from it and on to a different one. Is there a function I need to call to tell it to write the change to the file immediately? Or it's a bug?Component.onCompleted: { collectionIndex = api.memory.get('collectionIndex') || 0; currentGameIndex = api.memory.get('gameCollIndex' + collectionIndex) || 0; gamesettings.favorites = api.memory.get('settingsFavorites') || false; gamesettings.highlight = api.memory.get('settingsHighlight') || "#FF9E12"; gamesettings.scrollSpeed = api.memory.get('settingScrollSpeed') || 300; gamesettings.wheelArt = api.memory.get('settingsWheelArt') || true; gamesettings.fanArt = api.memory.get('settingsFanArt') || true; if (!api.memory.has('settingsFavorites')) {api.memory.set('settingsFavorites', false)} if (!api.memory.has('settingsHighlight')) {api.memory.set('settingsHighlight', "#FF9E12")} if (!api.memory.has('settingScrollSpeed')) {api.memory.set('settingScrollSpeed', 300)} if (!api.memory.has('settingsWheelArt')) {api.memory.set('settingsWheelArt', true)} if (!api.memory.has('settingsFanArt')) {api.memory.set('settingsFanArt', true)} }
-
@SinisterSpatula yes, the settings are saved on theme change and when closing Pegasus. Though now that I think about it, it might be better to save on change, like program settings, but it's still interesting that the file is not created for you.
EDIT: Ah yes on some platforms there's a crash on exit (a Qt bug), that might be the cause of it.
-
Ok, the latest version now saves the memory on change, let's see how it turns out.
-
Awesome! One thing that I wanted to ask about, and I know it's probably not a priority, because not many users are using it with small screen devices yet, is increasing the font size of the pegasus front end menu's. For now, the theme is properly sized but any of the pegasus menu's are tiny and mostly unreadable. If it's something you want to add to the future changes list, I don't expect it to be something that get's attention right away or anything.
-
@SinisterSpatula and here I was thinking it's too big :) Yes, I think I can make make it depend on the screen resolution, but that may need some work.
-
Still working on the theme mod. Today the settings menu is fully working, Settings menu has Highlight color, Background color, Game Description scrolling speed [fast, med, slow], which art to show in the background [Default, Fan Art, Screenshot, solid color], Wheel art cropping [crop, fit], and updating info (tells you the command to run from SSH to grab updates -- I'd love to add the code for doing it automagically but it seemed a bit over my head when I read about Qprocess). To do: Support Game "Tile" art as an alternate option from wheel art, which will be a composite of screenshot + wheel art, to give a "steam tiles" appearance. The settings menu might get a beautification. I'd still like to implement a favorites only view. I still need to finish the guide about how to do the composite game tiles via an "XML" recipe/custom mix. [I'm preferring to do it this way instead of having two layered images displayed theme-side, because of performance, it's better to bake the images together and optimize the size for the fastest loading and navigating of the grid on a pi zero.] Latest screenshots: https://imgur.com/a/yMaIvna
I have a work in progress guide I plan to provide to Gpi users who want to try it, and I'm sure the info in it is probably not correct or could be better. If anyone more familiar with Pegasus has any insight on how I can improve the guide: https://sinisterspatula.github.io/RetroflagGpiGuides/Pegasus
P.S. How do I filter and show just the favorites? I looked at the docs and example info but I really didn't quite understand, and couldn't find any other themes that already did this to gain insight from. I think my brain is having a hard time with -- how I would tell the grid to use the filtered collection instead of the one that the platform menu gave it.
-
@SinisterSpatula Nice progress! For creating the favorites list, basically when you have a list of items like
api.allGames
, you can create a filter object over it, which produces a list that only contains the items matching a particular condition. In this case, it would look something like this:// at the top of the file import SortFilterProxyModel 0.2 ... // somewhere in the file SortFilterProxyModel { id: filteredGames // the new model's name sourceModel: api.allGames // the original model filters: ValueFilter { // the filtering condition(s) roleName: "favorite" // "compare this field of each Game" value: true // "to this value, and include the Game in the new list if they match" enabled: mySettings.showOnlyFavs // optional: turn on/off this filter depending on some variable } } // then, in some other object that uses models GridView { model: filteredGames // the filter object above ... }
Sorting can be done similarly as well, and it's also possible to have multiple filters, or combine more than one of such filter objects. In most cases, the sorter/filter you want to use is RoleSorter and ValueFilter.
-
Hi @fluffypillow thanks for the info on favorites, I'm going to see if I can do that now. I'm having some problems using metadata and asset files I'm hoping you can help me. I am so stuck and confused right now. So, I'm trying to use cartridge artwork. I'm using
source: game.assets.cartridge
and in my metadata.pegasus.txt I have:assets.cartridge: media/cartridge/Bomberman Max - Blue Champion (USA).png
and I verify that everything is valid, true, and correct, and it mentions in the documentation that cartridge is supposed to be a valid asset, yet none of them are loading. The true path on the SD card is:/home/pi/RetroPie/roms/genesis/media/cartridge/
I guess for now I'll look at finding a different asset that will work, like poster perhaps. Unless I'm just missing something. In fact, all the various media when using the pegasus metadata all seem to not work, I must be missing something. -
Latest Video:
-
@SinisterSpatula
Your theme's looking good!Will it support cover/box art as well as the marquees you use in the videos?
-
@AndersHP Thanks! :D Yes currently for grid art it supports: Box Front art, screenshot, wheel, Steam tile's, and cartridges. For backgrounds, it can do: screenshot, fan art, the default image, or a solid color. All are changeable on a whim in the settings menu (select button). This is the guide I'm putting together for it: https://sinisterspatula.github.io/RetroflagGpiGuides/Pegasus
-
@SinisterSpatula
That's great! I don't know RetroFlag that well, but I guess this platform doesn't do anything differently than a Raspberry Pi-based Pegasus installation will?Can't wait to smash this theme on my new Gameboy build!
-
@AndersHP Yeah, the Retroflag Gpi is just a pi zero in a shell. The screen image is sent over GPIO that's about the only thing special about it. It's a killer design (the zero is inside a fake gameboy cart shell, and the PCB in the shell connects to the main body via a cart slot.
-
I tried the favorites filtering, and it does filter properly, but there are so many moving parts to the theme that it goes sideways fast, if I simply just update the grid itself with the new model, then other things that are pointing at variables like
collectionData, gameData, currentGameIdx
start to get wrong information. The grid indexes get changed so what used to be game index 10 is now game index 0, etc. -- I took another hard look and I'm thinking the theme is grabbing the current collection of games with this:property var currentCollection: api.collections.get(collectionIndex)
and I just am not figuring out how the sort proxy filter can be used with this, like it is a different Item Model type or something? -
@SinisterSpatula don't panic, it can be solved! :) The sorting/filtering produces a new list of objects (as it doesn't touch the source), so if some games get rearranged or removed then their index (ie. position) in the new list will also differ from what they have in the source model. The SortFilterProxyModel objects have two handy functions for this:
int mapToSource(int proxyRow)
: based on an index from the sorted/filtered list, it tells you the game's position in the original modelint mapFromSource(int sourceRow)
: based on an index from the original model, it tells you the game's new position in the sorted/filtered list
Both return
-1
for missing items. The original documentation is here.I'm trying to use cartridge artwork
I've just tried this, with the same filename and such, but it seems to work fine for me. Do you see any loading errors in the log? There should be either a warning related to the metadata file if the value could not be read, or there should be a QML error saying that the image could not be opened.
Also I'm happy to see the video progress too, nice!
-
@SinisterSpatula When I made the theme originally it was mainly just me learning QML so I was doing a lot of bad practices. Ultimately really the best way to make these themes (and if I ever get around to doing a proper cleanup pass I'll do this) is to keep all your variables stored in one place and pass them down rather than referencing them again and again. @fluffypillow may want to correct me if I'm wrong on this (and he's already provided a solution above), but ideally these variables you are getting and setting should get stored in the theme.qml and passed down each time.
I mean it's kind of annoying having to do this rather than being able to reference the top level directly within (maybe this is possible I don't know) but at least then you have clean references that only need to be updated in one place then.
-
Thanks for the replies guys. I'm still wracking my brain trying to figure it out, lol. But I was having similar thoughts about it. Was just thinking, I need to refactor the code so that I have a "clean, focused" set of variables that everything else will access from. So that I know everything is grabbing and using the same information across all places. What I am really struggling with is, when using the ProxySortFilter it provides me with a model. I guess I'm trying to figure out how to best use that model as a "variable" so that for example, the game's title at the top of the screen, can access the currently selected game's name. Currently, the game details view, and the Title of the game, and launching of the game, etc, are all pulling from
readonly property var currentGame: currentCollection.games.get(currentGameIndex)
so I'm trying to figure out, how I can take the results from the ProxySortFilter, and place it into currentGame, by using the mapFromSource(int sourceRow). I guess I really need some hand holding on this LOL. Maybe, in the theme.qml main file, I just need to maintain two sets of data, one that is filtered, and one that is not. And a third set which everything accesses. Then I would swap the third with the first or second.Another issue I'm thinking about, I noticed when I broke a lot of the logic, that the grid view scrolling actually gained a lot of performance. I think it's being slowed down by the logic of switching the background art immediately upon moving to the next grid item. Wondering if there is a simple way to wait for scrolling to stop for 5 seconds, before switching the background art.
It almost seems like, maybe I just need to redo the DetailsRequested() to include the game that belongs to the grid item? That way it shows the proper game always, when being opened. And the game title just needs a way to point at the currently selected grid items, modelData?
Contributions to the project are always appreciated, so if you would like to support us with a donation you can do so here.
Hosting provided by Mythic-Beasts. See the Hosting Information page for more information.