├── .nojekyll ├── Bottombar ├── BottomBarIcons.qml └── IconPair.qml ├── EXTRAINFO.md ├── Extra ├── ClockBar.qml ├── Colcon.qml └── IconFont.qml ├── GameItems ├── GICusart.qml ├── GINormal.qml └── VideoPlayer.qml ├── LICENSE ├── Localization.qml ├── MODIFICATIONS.md ├── README.md ├── Theme ├── All.qml ├── Collections.qml ├── Home.qml ├── PegaKey │ ├── KeyButton.qml │ ├── Keyboard.qml │ └── KeyboardObject.qml └── Settings.qml ├── assets ├── SAFELY_REMOVABLE │ ├── OLD_DOCUMENTATION.md │ ├── library-icons-font │ │ ├── README.txt │ │ ├── config.json │ │ ├── css │ │ │ ├── animation.css │ │ │ ├── library-icons-font-codes.css │ │ │ ├── library-icons-font-embedded.css │ │ │ ├── library-icons-font-ie7-codes.css │ │ │ ├── library-icons-font-ie7.css │ │ │ └── library-icons-font.css │ │ ├── demo.html │ │ └── font │ │ │ ├── library-icons-font.eot │ │ │ ├── library-icons-font.svg │ │ │ ├── library-icons-font.ttf │ │ │ ├── library-icons-font.woff │ │ │ └── library-icons-font.woff2 │ ├── old_screenshots │ │ ├── old_screenshot_1.png │ │ ├── old_screenshot_2.png │ │ ├── old_screenshot_3.png │ │ ├── old_screenshot_4.png │ │ ├── old_screenshot_5.png │ │ ├── old_screenshot_6.png │ │ ├── old_screenshot_7.png │ │ ├── old_screenshot_8.png │ │ └── old_screenshot_9.png │ ├── screenshot_1.png │ ├── screenshot_2.png │ ├── screenshot_3.png │ ├── screenshot_4.png │ ├── screenshot_5.png │ ├── screenshot_6.png │ ├── screenshot_7.png │ ├── screenshot_8.png │ ├── screenshot_9.png │ └── website │ │ ├── commonelements.js │ │ ├── gallery.html │ │ ├── install.html │ │ ├── main.html │ │ └── styles │ │ ├── Outfit-Variable.ttf │ │ ├── fonts.css │ │ └── main.css ├── audio │ ├── accept.wav │ ├── back.wav │ ├── favorite.wav │ ├── game.wav │ ├── nav.wav │ ├── switchB.wav │ ├── switchF.wav │ ├── tab.wav │ └── type.wav ├── backgrounds │ ├── dark-1.jpg │ ├── dark-2.jpg │ ├── light-1.jpg │ └── light-2.jpg ├── font │ ├── Gilroy-ExtraBold.otf │ ├── Gilroy-Light.otf │ ├── NotoSansJP-ExtraBold.ttf │ ├── NotoSansJP-Light.ttf │ └── library-icons-font.ttf ├── logo │ └── banner │ │ ├── 3do.jpg │ │ ├── 3ds.jpg │ │ ├── all.jpg │ │ ├── amiga.jpg │ │ ├── amstradcpc.jpg │ │ ├── android.jpg │ │ ├── apple2.jpg │ │ ├── arcade.jpg │ │ ├── atari2600.jpg │ │ ├── atari5200.jpg │ │ ├── atari7800.jpg │ │ ├── atarijaguar.jpg │ │ ├── atarilynx.jpg │ │ ├── atarist.jpg │ │ ├── atomiswave.jpg │ │ ├── c64.jpg │ │ ├── cdi.jpg │ │ ├── colecovision.jpg │ │ ├── cps1.jpg │ │ ├── cps2.jpg │ │ ├── cps3.jpg │ │ ├── daphne.jpg │ │ ├── dreamcast.jpg │ │ ├── empty.jpg │ │ ├── fba.jpg │ │ ├── fbneo.jpg │ │ ├── fds.jpg │ │ ├── flash.jpg │ │ ├── gamegear.jpg │ │ ├── gb.jpg │ │ ├── gba.jpg │ │ ├── gbc.jpg │ │ ├── gc.jpg │ │ ├── generic.png │ │ ├── genesis.jpg │ │ ├── gog.jpg │ │ ├── gog_alt.jpg │ │ ├── intellivision.jpg │ │ ├── lutris.jpg │ │ ├── mame.jpg │ │ ├── mastersystem.jpg │ │ ├── megadrive.jpg │ │ ├── msx.jpg │ │ ├── msx2.jpg │ │ ├── n64.jpg │ │ ├── nds.jpg │ │ ├── neogeo.jpg │ │ ├── neogeocd.jpg │ │ ├── nes.jpg │ │ ├── ngp.jpg │ │ ├── ngpc.jpg │ │ ├── pc.jpg │ │ ├── pcengine.jpg │ │ ├── pcfx.jpg │ │ ├── pico8.jpg │ │ ├── ports.jpg │ │ ├── ps2.jpg │ │ ├── ps3.jpg │ │ ├── psp.jpg │ │ ├── psx.jpg │ │ ├── saturn.jpg │ │ ├── scumm.jpg │ │ ├── sega32x.jpg │ │ ├── segacd.jpg │ │ ├── snes.jpg │ │ ├── source-note.txt │ │ ├── steam.jpg │ │ ├── steam_alt.jpg │ │ ├── str.jpg │ │ ├── switch.jpg │ │ ├── tic80.jpg │ │ ├── turbografx16.jpg │ │ ├── vectrex.jpg │ │ ├── virtualboy.jpg │ │ ├── wii.jpg │ │ ├── wiiu.jpg │ │ ├── wiiware.jpg │ │ ├── windows.jpg │ │ ├── winuwp.jpg │ │ └── zxspectrum.jpg └── theme │ ├── logo.png │ └── logo.svg ├── index.html ├── theme.cfg └── theme.qml /.nojekyll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Fr75s/library/dd44cb3c00ca14b1bc8eaadb96f385a09b372984/.nojekyll -------------------------------------------------------------------------------- /Bottombar/BottomBarIcons.qml: -------------------------------------------------------------------------------- 1 | import QtQuick 2.8 2 | import QtMultimedia 5.9 3 | import QtQuick.Layouts 1.15 4 | import QtGraphicalEffects 1.15 5 | import QtQuick.Window 2.15 6 | 7 | Item { 8 | /* Button icons for the bottom bar 9 | * Shown when button indicators are enabled 10 | * 11 | */ 12 | 13 | width: sw 14 | height: bottomBarSizeIndexToSize[settings["barSize"]] 15 | 16 | property bool limitHeight: (height > sh * 0.0525) 17 | 18 | anchors.bottom: parent.bottom 19 | 20 | /* We define 2 items, one for the right and one for the left 21 | * It would be difficult to separate these. 22 | * 23 | */ 24 | 25 | // Right Buttons 26 | Item { 27 | width: parent.width / 2 28 | height: parent.height 29 | 30 | anchors.bottom: parent.bottom 31 | anchors.right: parent.right 32 | 33 | // Right Row 34 | Row { 35 | id: rightRow 36 | 37 | width: parent.width 38 | height: limitHeight ? bottomBarSizeIndexToSize["small"] : parent.height 39 | 40 | spacing: parent.width * .01 41 | 42 | layoutDirection: Qt.RightToLeft 43 | 44 | anchors.verticalCenter: parent.verticalCenter 45 | anchors.right: parent.right 46 | anchors.rightMargin: parent.width * .01 47 | 48 | // A Button Actions 49 | IconPair { 50 | height: parent.height * .8 51 | 52 | src: icons.btnScheme[settings.btnsScheme].A 53 | 54 | // Label for Home, Search, Collections & Settings respectively. 55 | // Same pattern for each IconPair. 56 | label: [loc.bottomBar_aSelect, (isFeed ? loc.bottomBar_aPlay : loc.bottomBar_aSelect), loc.bottomBar_aSelect, loc.bottomBar_aSetting] 57 | 58 | anchors.verticalCenter: parent.verticalCenter 59 | } 60 | 61 | // B Button Actions 62 | IconPair { 63 | height: parent.height * .8 64 | 65 | src: icons.btnScheme[settings.btnsScheme].B 66 | 67 | label: ["", (isFeed ? "" : loc.bottomBar_bKeyboard), loc.bottomBar_bExit, ""] 68 | 69 | anchors.verticalCenter: parent.verticalCenter 70 | } 71 | 72 | // Y Button Actions 73 | IconPair { 74 | height: parent.height * .8 75 | 76 | src: icons.btnScheme[settings.btnsScheme].Y 77 | 78 | label: [loc.bottomBar_yFavorite, (isFeed ? loc.bottomBar_yNext : loc.bottomBar_yKeyboard), loc.bottomBar_yFavorite, loc.bottomBar_yInfo] 79 | 80 | anchors.verticalCenter: parent.verticalCenter 81 | } 82 | } 83 | } 84 | 85 | // Left Buttons 86 | Item { 87 | width: parent.width / 2 88 | height: parent.height 89 | 90 | anchors.bottom: parent.bottom 91 | anchors.left: parent.left 92 | 93 | // Left Row 94 | Row { 95 | id: leftRow 96 | 97 | width: parent.width 98 | height: limitHeight ? bottomBarSizeIndexToSize["small"] : parent.height 99 | 100 | spacing: parent.width * .01 101 | 102 | layoutDirection: Qt.LeftToRight 103 | 104 | anchors.verticalCenter: parent.verticalCenter 105 | anchors.left: parent.left 106 | anchors.leftMargin: parent.width * .01 107 | 108 | // L1, left blank to go with R1 109 | IconPair { 110 | height: parent.height * .8 111 | 112 | src: icons.btnScheme[settings.btnsScheme].L1 113 | 114 | 115 | label: [" ", " ", " ", " "] 116 | 117 | anchors.verticalCenter: parent.verticalCenter 118 | } 119 | 120 | // R1, indicating change page 121 | IconPair { 122 | height: parent.height * .8 123 | 124 | src: icons.btnScheme[settings.btnsScheme].R1 125 | 126 | label: [loc.bottomBar_changePage, loc.bottomBar_changePage, loc.bottomBar_changePage, loc.bottomBar_changePage] 127 | 128 | anchors.verticalCenter: parent.verticalCenter 129 | } 130 | 131 | IconPair { 132 | height: parent.height * .8 133 | 134 | src: icons.btnScheme[settings.btnsScheme].L2 135 | 136 | label: ["", loc.all_feed, "", ""] 137 | 138 | anchors.verticalCenter: parent.verticalCenter 139 | } 140 | 141 | // X Button Actions 142 | IconPair { 143 | height: parent.height * .8 144 | 145 | src: icons.btnScheme[settings.btnsScheme].X 146 | 147 | label: ["", (isFeed ? "" : loc.bottomBar_xKeyboard), "", loc.bottomBar_xNext] 148 | 149 | anchors.verticalCenter: parent.verticalCenter 150 | } 151 | 152 | } 153 | } 154 | } 155 | -------------------------------------------------------------------------------- /Bottombar/IconPair.qml: -------------------------------------------------------------------------------- 1 | import QtQuick 2.8 2 | import QtMultimedia 5.9 3 | import QtQuick.Layouts 1.15 4 | import QtGraphicalEffects 1.15 5 | import QtQuick.Window 2.15 6 | 7 | Row { 8 | /* IconPair 9 | * Defines an icon and text for button icons 10 | * 11 | */ 12 | 13 | // Image Source 14 | property string src: "" 15 | 16 | // Labels for each page, with each element corresponding to each page 17 | property var label: ["0", "1", "2", "3"] 18 | 19 | spacing: (textContent.width + height) * 0.05 20 | 21 | width: textContent.width + height + spacing 22 | 23 | visible: (label[menu] != "") 24 | 25 | Item { // Home 26 | width: height 27 | height: parent.height * .8 28 | anchors.verticalCenter: parent.verticalCenter 29 | // Icon 30 | Text { 31 | text: src 32 | anchors.centerIn: parent 33 | font { 34 | family: icons.name; 35 | pixelSize: parent.height * .6 36 | } 37 | color: colors["bottomIcons"] 38 | } 39 | } 40 | 41 | // Text 42 | Text { 43 | id: textContent 44 | height: parent.height 45 | width: contentWidth 46 | 47 | text: label[menu] 48 | color: colors["bottomIcons"] 49 | 50 | font.pixelSize: parent.height * .6 51 | font.family: gilroyLight.name 52 | verticalAlignment: Text.AlignVCenter 53 | 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /EXTRAINFO.md: -------------------------------------------------------------------------------- 1 | # Extra Information for Library 2 | 3 | This document contains some extra information regarding some features of Library. It will provide some tips regarding the in-built features of Library, with no code modification necessary. Code modification stuff can be found in `MODIFICATIONS.md`. 4 | 5 | ## Search Modes (1.5.0+) 6 | 7 | There are currently **4** search modes in Library: Regular, Limited, Fuzzy, and Raw. 8 | 9 | - Regular: Finds any games which contain the given search anywhere in their title. Not case sensitive. 10 | - Limited: Finds any games which contain the given search at the beginning of their title. Not case sensitive. 11 | - Fuzzy: Finds games using a command prompt shorthand style of searching. Characters are matched in order and do not need to be adjacent to eachother (for example, unlike in Regular/Limited search, "ut" would match "Multiverse"). Capital letters let you enforce word boundaries by forcing the next letter to be at the beginning of a word (e.g. "BB" would match "Bugle Boggle" but not "Bugle Trouble", while "bb" would match both). While the syntax of fuzzy search is case-sensitive, the matching itself isn't (so, for example, "BB" would match both "Bugle Boggle" and "bugle boggle"). 12 | - Raw: Finds games by treating the given search as a raw RegEx pattern. You can use any RegEx symbols to match game titles. 13 | 14 | 15 | ## Replacing the Backgrounds (1.4.0+) 16 | 17 | You can easily add/change the backgrounds shown in Library. 18 | 19 | To do this, go to `assets/backgrounds` in the theme's root directory (`[LIBRARY FOLDER]/assets/backgrounds`). Then, add your desired backgrounds, but be sure to add one for light mode and one for dark mode. Rename the backgrounds to `light-[number].jpg` and `dark-[number].jpg`, where `[number]` is the next number from the last backgrounds (which would be 3 if no backgrounds have been added, as Library comes with 2 sets of backgrounds.). Now, you can change to your background by finding the "Change Background" option. 20 | 21 | You can also set the color of the plain background by setting the color for `plainBG`. To learn more about changing colors, see [Custom Color Schemes](#custom-color-schemes). 22 | -------------------------------------------------------------------------------- /Extra/ClockBar.qml: -------------------------------------------------------------------------------- 1 | import QtQuick 2.8 2 | import QtMultimedia 5.9 3 | import QtQuick.Layouts 1.15 4 | import QtGraphicalEffects 1.15 5 | import QtQuick.Window 2.15 6 | 7 | Item { 8 | // A simple clock bar at the top of the screen 9 | 10 | width: parent.width 11 | height: parent.height * 0.035 12 | 13 | Rectangle { 14 | width: parent.width 15 | height: parent.height 16 | 17 | opacity: 0.5 18 | color: colors["clockBarBG"] 19 | } 20 | 21 | Text { 22 | /* I have known of this method of a time text since first dabbling with Pegasus 23 | * It's from somewhere, but I have no idea where. 24 | */ 25 | id: currentTime 26 | 27 | // Set Time 28 | function set() { 29 | currentTime.text = settings["24hClock"] ? Qt.formatTime(new Date(), "hh:mm") : Qt.formatTime(new Date(), "hh:mm AP"); 30 | } 31 | 32 | // Runs the timer to update the time every second 33 | Timer { 34 | id: currentTimeTextTimer 35 | interval: 1000 // Run the timer every second 36 | repeat: true 37 | running: true 38 | triggeredOnStart: true // Start immediately 39 | onTriggered: currentTime.set() 40 | } 41 | 42 | width: parent.width * 0.95 43 | anchors.horizontalCenter: parent.horizontalCenter 44 | height: parent.height 45 | 46 | horizontalAlignment: Text.AlignLeft 47 | verticalAlignment: Text.AlignVCenter 48 | 49 | color: colors["text"] 50 | font.family: gilroyExtraBold.name 51 | font.pixelSize: height / 2 52 | font.bold: true 53 | } 54 | 55 | Text { 56 | id: batteryIcon 57 | 58 | width: parent.width * 0.002 59 | height: parent.height 60 | 61 | anchors.left: currentTime.left 62 | anchors.leftMargin: currentTime.contentWidth + parent.width * 0.018 63 | 64 | text: isNaN(api.device.batteryPercent) ? "" : getBatteryIcon(api.device.batteryPercent) 65 | 66 | font { 67 | family: icons.name; 68 | pixelSize: height / 2 69 | } 70 | 71 | color: colors["text"] 72 | } 73 | 74 | Text { 75 | /* Lists the battery, not much more. 76 | */ 77 | id: battery 78 | 79 | width: contentWidth 80 | height: parent.height 81 | 82 | anchors.left: currentTime.left 83 | anchors.leftMargin: currentTime.contentWidth + parent.width * 0.02 84 | 85 | horizontalAlignment: Text.AlignLeft 86 | verticalAlignment: Text.AlignVCenter 87 | 88 | text: isNaN(api.device.batteryPercent) ? "" : formPercent(api.device.batteryPercent) + "%" 89 | color: colors["text"] 90 | font.family: gilroyExtraBold.name 91 | font.pixelSize: height / 2 92 | } 93 | 94 | 95 | // Makes battery percentage readable (rather than a random decimal number) 96 | function getBatteryIcon(percent) { 97 | 98 | // Battery Percent must be less than or equal to KEY to be VALUE 99 | if (api.device.batteryCharging && api.device.batteryPercent <= 1) { 100 | return "\ue837"; 101 | } else { 102 | var batteryConvert = { 103 | 5: "\ue82c", 104 | 10: "\ue82d", 105 | 20: "\ue82e", 106 | 30: "\ue82f", 107 | 40: "\ue830", 108 | 50: "\ue831", 109 | 60: "\ue832", 110 | 70: "\ue833", 111 | 80: "\ue834", 112 | 90: "\ue835", 113 | 100: "\ue836", 114 | } 115 | 116 | var clean_percent = Math.round(percent * 100); 117 | 118 | var index = 0; 119 | var range_r = Object.keys(batteryConvert)[index]; 120 | while (clean_percent > range_r && clean_percent <= 100) { 121 | index += 1; 122 | range_r = Object.keys(batteryConvert)[index]; 123 | } 124 | 125 | return batteryConvert[range_r]; 126 | } 127 | } 128 | 129 | function formPercent(percent) { 130 | return Math.round(percent * 100); 131 | } 132 | 133 | } 134 | -------------------------------------------------------------------------------- /Extra/Colcon.qml: -------------------------------------------------------------------------------- 1 | import QtQuick 2.8 2 | import QtMultimedia 5.9 3 | import QtQuick.Layouts 1.15 4 | import QtGraphicalEffects 1.15 5 | import QtQuick.Window 2.15 6 | 7 | FocusScope { 8 | 9 | /* A tool to convert Launchbox items to actual counterparts 10 | * Directly from neoretrō: https://github.com/valsou/neoretro 11 | * Used in GICusart. 12 | */ 13 | 14 | function clearShortname(shortname) { 15 | return dataLaunchbox[shortname] ? dataLaunchbox[shortname] : shortname 16 | } 17 | 18 | property variant dataLaunchbox: { 19 | "amstrad cpc" : "amstradcpc", 20 | "apple ii" : "apple2", 21 | "atari 2600" : "atari2600", 22 | "atari 5200" : "atari5200", 23 | "atari st" : "atarist", 24 | "atari 7800" : "atari7800", 25 | "atari lynx" : "atarilynx", 26 | "atari jaguar" : "atarijaguar", 27 | "capcom cps1" : "cps1", 28 | "capcom cps2" : "cps2", 29 | "capcom cps3" : "cps3", 30 | "commodore 64" : "c64", 31 | "commodore amiga" : "amiga", 32 | "mattel intellivision" : "intellivision", 33 | "microsoft msx" : "msx", 34 | "microsoft msx2" : "msx2", 35 | "nec turbografx-16" : "turbografx16", 36 | "pc engine supergrafx" : "supergrafx", 37 | "nec pc-fx" : "pcfx", 38 | "nintendo entertainment system" : "nes", 39 | "nintendo famicom disk system" : "fds", 40 | "nintendo virtual boy" : "virtualboy", 41 | "nintendo game boy" : "gb", 42 | "super nintendo entertainment system" : "snes", 43 | "nintendo 64" : "n64", 44 | "nintendo game boy color" : "gbc", 45 | "nintendo game boy advance" : "gba", 46 | "nintendo gamecube" : "gc", 47 | "nintendo ds" : "nds", 48 | "nintendo wii" : "wii", 49 | "nintendo 3ds" : "3ds", 50 | "nintendo wii u" : "wiiu", 51 | "nintendo switch" : "switch", 52 | "3do interactive multiplayer" : "3do", 53 | "sammy atomiswave" : "atomiswave", 54 | "scummvm" : "scumm", 55 | "sega master system" : "mastersystem", 56 | "sega genesis" : "genesis", 57 | "sega mega drive" : "megadrive", 58 | "sega game gear" : "gamegear", 59 | "sega cd" : "segacd", 60 | "sega 32x" : "sega32x", 61 | "sega saturn" : "saturn", 62 | "sega dreamcast" : "dreamcast", 63 | "sinclair zx spectrum" : "zxspectrum", 64 | "gce vectrex" : "vectrex", 65 | "snk neo geo aes" : "neogeo", 66 | "snk neo geo mvs": "neogeo", 67 | "snk neo geo cd" : "neogeocd", 68 | "snk neo geo pocket" : "ngp", 69 | "snk neo geo pocket color" : "ngpc", 70 | "sony playstation" : "psx", 71 | "sony playstation 2" : "ps2", 72 | "sony playstation 3" : "ps3", 73 | "sony psp" : "psp", 74 | "final burn alpha" : "fba", 75 | "final burn neo" : "fbneo" 76 | } 77 | } 78 | -------------------------------------------------------------------------------- /Extra/IconFont.qml: -------------------------------------------------------------------------------- 1 | import QtQuick 2.8 2 | 3 | // Custom Font for icons 4 | FontLoader { 5 | id: icons; 6 | 7 | property string allgames: '\ue800'; 8 | property string nav_collections: '\ue801'; 9 | property string nav_feed: '\ue802'; 10 | property string nav_home: '\ue803'; 11 | property string nav_search: '\ue804'; 12 | property string nav_settings: '\ue805'; 13 | property string touch_up: '\ue806'; 14 | property string input_universal_a: '\ue807'; 15 | property string input_universal_x: '\ue808'; 16 | property string input_universal_lb: '\ue809'; 17 | property string input_universal_lt: '\ue80a'; 18 | property string input_universal_b: '\ue80b'; 19 | property string input_universal_rb: '\ue80c'; 20 | property string input_universal_rt: '\ue80d'; 21 | property string input_universal_y: '\ue80e'; 22 | property string input_xbox_a: '\ue80f'; 23 | property string input_xbox_x: '\ue810'; 24 | property string input_xbox_lb: '\ue811'; 25 | property string input_xbox_lt: '\ue812'; 26 | property string input_xbox_b: '\ue813'; 27 | property string input_xbox_rb: '\ue814'; 28 | property string input_xbox_rt: '\ue815'; 29 | property string input_xbox_y: '\ue816'; 30 | property string input_ps_a: '\ue817'; 31 | property string input_ps_x: '\ue818'; 32 | property string input_ps_lb: '\ue819'; 33 | property string input_ps_lt: '\ue81a'; 34 | property string input_ps_b: '\ue81b'; 35 | property string input_ps_rb: '\ue81c'; 36 | property string input_universal_start: '\ue81d'; 37 | property string input_universal_select: '\ue81e'; 38 | property string input_xbox_start: '\ue81f'; 39 | property string input_xbox_select: '\ue820'; 40 | property string input_ps_rt: '\ue821'; 41 | property string input_ps_y: '\ue822'; 42 | property string input_ps_start: '\ue823'; 43 | property string input_ps_select: '\ue824'; 44 | property string star: '\ue825'; 45 | property string star_empty: '\ue826'; 46 | property string meta_date: '\ue827'; 47 | property string meta_dev: '\ue828'; 48 | property string meta_genre: '\ue829'; 49 | property string meta_publisher: '\ue82a'; 50 | property string meta_players: '\ue82b'; 51 | property string battery_0: '\ue82c'; 52 | property string battery_10: '\ue82d'; 53 | property string battery_20: '\ue82e'; 54 | property string battery_30: '\ue82f'; 55 | property string battery_40: '\ue830'; 56 | property string battery_50: '\ue831'; 57 | property string battery_60: '\ue832'; 58 | property string battery_70: '\ue833'; 59 | property string battery_80: '\ue834'; 60 | property string battery_90: '\ue835'; 61 | property string battery_100: '\ue836'; 62 | property string battery_charging: '\ue837'; 63 | property string clock: '\ue838'; 64 | property string input_nintendo_zl: '\ue83b'; 65 | property string input_nintendo_zr: '\ue83c'; 66 | property string input_sd_l2: '\ue83d'; 67 | property string input_sd_r2: '\ue83e'; 68 | property string input_sd_l1: '\ue83f'; 69 | property string input_sd_r1: '\ue840'; 70 | property string input_nintendo_l: '\ue841'; 71 | property string input_nintendo_r: '\ue842'; 72 | property string input_sd_select: '\ue843'; 73 | property string input_sd_start: '\ue844'; 74 | property string input_nintendo_sl: '\ue845'; 75 | property string input_nintendo_sr: '\ue846'; 76 | property string star_half: '\uf123'; 77 | property string toggle_off: '\uf204'; 78 | property string toggle_on: '\uf204'; 79 | 80 | // Button schemes 81 | property var btnScheme: { 82 | "universal": { 83 | A: icons.input_universal_a, 84 | X: icons.input_universal_x, 85 | L1: icons.input_universal_lb, 86 | L2: icons.input_universal_lt, 87 | B: icons.input_universal_b, 88 | R1: icons.input_universal_rb, 89 | R2:icons.input_universal_rt, 90 | Y: icons.input_universal_y, 91 | Start: icons.input_universal_start, 92 | Select: icons.input_universal_select 93 | }, 94 | "universal_jp": { 95 | A: icons.input_universal_b, 96 | X: icons.input_universal_y, 97 | L1: icons.input_universal_lb, 98 | L2: icons.input_universal_lt, 99 | B: icons.input_universal_a, 100 | R1: icons.input_universal_rb, 101 | R2:icons.input_universal_rt, 102 | Y: icons.input_universal_x, 103 | Start: icons.input_universal_start, 104 | Select: icons.input_universal_select 105 | }, 106 | "xbox": { 107 | A: icons.input_xbox_a, 108 | X: icons.input_xbox_x, 109 | L1: icons.input_xbox_lb, 110 | L2: icons.input_xbox_lt, 111 | B: icons.input_xbox_b, 112 | R1: icons.input_xbox_rb, 113 | R2:icons.input_xbox_rt, 114 | Y: icons.input_xbox_y, 115 | Start: icons.input_xbox_start, 116 | Select: icons.input_xbox_select 117 | }, 118 | "ps": { 119 | A: icons.input_ps_a, 120 | X: icons.input_ps_x, 121 | L1: icons.input_ps_lb, 122 | L2: icons.input_ps_lt, 123 | B: icons.input_ps_b, 124 | R1: icons.input_ps_rb, 125 | R2:icons.input_ps_rt, 126 | Y: icons.input_ps_y, 127 | Start: icons.input_ps_start, 128 | Select: icons.input_ps_select 129 | }, 130 | "ps_jp": { 131 | A: icons.input_ps_b, 132 | X: icons.input_ps_y, 133 | L1: icons.input_ps_lb, 134 | L2: icons.input_ps_lt, 135 | B: icons.input_ps_a, 136 | R1: icons.input_ps_rb, 137 | R2:icons.input_ps_rt, 138 | Y: icons.input_ps_x, 139 | Start: icons.input_ps_start, 140 | Select: icons.input_ps_select 141 | }, 142 | "nintendo": { 143 | A: icons.input_xbox_a, 144 | X: icons.input_xbox_x, 145 | L1: icons.input_nintendo_l, 146 | L2: icons.input_nintendo_zl, 147 | B: icons.input_xbox_b, 148 | R1: icons.input_nintendo_r, 149 | R2:icons.input_nintendo_zr, 150 | Y: icons.input_xbox_y, 151 | Start: icons.input_universal_start, 152 | Select: icons.input_universal_select 153 | }, 154 | "steam_deck": { 155 | A: icons.input_xbox_a, 156 | X: icons.input_xbox_x, 157 | L1: icons.input_sd_l1, 158 | L2: icons.input_sd_l2, 159 | B: icons.input_xbox_b, 160 | R1: icons.input_sd_r1, 161 | R2:icons.input_sd_r2, 162 | Y: icons.input_xbox_y, 163 | Start: icons.input_sd_start, 164 | Select: icons.input_sd_select 165 | } 166 | } 167 | 168 | // This list needs to be separate to allow for customization of order, rather than going 169 | // by each key alphabetically in the convert object 170 | property var btnSchemeOrder: {0: "universal", 1: "universal_jp", 2: "xbox", 3: "ps", 4: "ps_jp", 5: "nintendo", 6: "steam_deck"} 171 | // Converts the indexes in btnScheme to the names that are displayed 172 | // This makes it so that what's displayed is possible to customize and localize 173 | property var btnNameConvert: { 174 | "universal": "universal", 175 | "universal_jp": "universal JP", 176 | "xbox": "xbox", 177 | "ps": "playstation", 178 | "ps_jp": "playstation JP", 179 | "nintendo": "nintendo", 180 | "steam_deck": "steam deck" 181 | } 182 | 183 | source: "../assets/font/library-icons-font.ttf"; 184 | } 185 | -------------------------------------------------------------------------------- /GameItems/GICusart.qml: -------------------------------------------------------------------------------- 1 | import QtQuick 2.8 2 | import QtMultimedia 5.9 3 | import QtQuick.Layouts 1.15 4 | import QtGraphicalEffects 1.15 5 | import QtQuick.Window 2.15 6 | 7 | Item { 8 | property var currentItem: modelData 9 | property var art: "./assets/logo/banner/empty.jpg" 10 | 11 | id: gameItem 12 | 13 | width: parent.width * 1.00 14 | height: parent.height 15 | 16 | // Name 17 | Text{ 18 | id: collectName 19 | text: currentItem.name 20 | 21 | width: parent.width * 0.75 22 | z: gameItemImage.z + 2 23 | 24 | anchors.horizontalCenter: parent.horizontalCenter 25 | anchors.top: parent.top 26 | anchors.topMargin: parent.height * 0.1 27 | 28 | wrapMode: Text.WordWrap 29 | 30 | font.family: gilroyExtraBold.name 31 | font.bold: true 32 | 33 | color: "white" 34 | font.pixelSize: vpx(10) * (3 / settings["collectionRows"]) 35 | visible: !(settings["videoPlayback"] && doubleFocus && currentItem.assets.videoList.length) 36 | } 37 | 38 | /* 39 | Rectangle { 40 | color: "black" 41 | 42 | width: collectName.width + vpx(20) 43 | height: collectName.height + vpx(10) 44 | anchors.centerIn: collectName 45 | 46 | z: gameItemImage.z + 1 47 | } 48 | */ 49 | 50 | // Top bar 51 | Rectangle { 52 | id: customTopBar 53 | width: parent.width 54 | height: parent.height * .3 55 | 56 | anchors.right: parent.right 57 | anchors.top: parent.top 58 | 59 | color: settings["blurredCollections"] ? "#60000000" : "#90000000" 60 | 61 | z: gameItemImage.z + 1 62 | //radius: roundedGames ? height / roundedGamesRadiusFactor / .3 : 0 63 | visible: false 64 | } 65 | 66 | // Collection Image 67 | Image { 68 | id: gameItemImage 69 | width: parent.width 70 | height: parent.height 71 | 72 | anchors.centerIn: parent 73 | fillMode: Image.PreserveAspectCrop 74 | 75 | asynchronous: true 76 | 77 | source: ".././assets/logo/banner/" + cc.clearShortname(currentItem.shortName) + ".jpg" 78 | visible: false 79 | 80 | onStatusChanged: { 81 | if (status == Image.Error) { 82 | gameItemImage.source = ".././assets/logo/banner/generic.png"; 83 | } 84 | } 85 | 86 | VideoPlayer { 87 | game: currentItem 88 | 89 | width: parent.width 90 | height: parent.height 91 | anchors.centerIn: parent 92 | 93 | playing: settings["videoPlayback"] && doubleFocus 94 | noSound: settings["nosfx"] 95 | } 96 | } 97 | 98 | 99 | Rectangle { 100 | id: gameItemMask 101 | anchors.fill: parent 102 | visible: false 103 | 104 | radius: settings["roundedGames"] ? height / roundedGamesRadiusFactor : 0 105 | } 106 | 107 | Rectangle { 108 | id: customTopMask 109 | width: parent.width 110 | height: customTopBar.height 111 | visible: false 112 | 113 | radius: settings["roundedGames"] ? height / roundedGamesRadiusFactor / .3 : 0 114 | 115 | Rectangle { 116 | width: parent.width 117 | height: parent.height / 2 118 | 119 | anchors.bottom: parent.bottom 120 | } 121 | } 122 | 123 | OpacityMask { 124 | id: gameItemRounded 125 | anchors.fill: gameItemImage 126 | source: gameItemImage 127 | maskSource: gameItemMask 128 | visible: !settings["blurredCollections"] 129 | } 130 | 131 | // Blur 132 | FastBlur { 133 | id: gameItemBlur 134 | visible: false 135 | anchors.fill: gameItemRounded 136 | source: gameItemRounded 137 | radius: 48 138 | } 139 | 140 | OpacityMask { 141 | id: gameItemBlurRounded 142 | anchors.fill: gameItemBlur 143 | source: gameItemBlur 144 | maskSource: gameItemMask 145 | 146 | visible: settings["blurredCollections"] 147 | } 148 | 149 | 150 | 151 | OpacityMask { 152 | anchors.fill: customTopBar 153 | source: customTopBar 154 | maskSource: customTopMask 155 | visible: !(settings["videoPlayback"] && doubleFocus && currentItem.assets.videoList.length) 156 | } 157 | 158 | // Drop Shadow 159 | DropShadow { 160 | width: parent.width 161 | height: parent.height 162 | 163 | source: settings["blurredCollections"] ? gameItemBlurRounded : gameItemRounded 164 | 165 | anchors.centerIn: parent 166 | 167 | opacity: giShadowOp 168 | 169 | radius: giShadowRad 170 | samples: giShadowRad * 2 + 1 171 | z: gameItemImage.z - 1 172 | } 173 | } 174 | -------------------------------------------------------------------------------- /GameItems/GINormal.qml: -------------------------------------------------------------------------------- 1 | import QtQuick 2.8 2 | import QtMultimedia 5.9 3 | import QtQuick.Layouts 1.15 4 | import QtGraphicalEffects 1.15 5 | import QtQuick.Window 2.15 6 | 7 | Item { 8 | id: gameItem 9 | 10 | // The standard gameItem, showing for all instances where games are shown. 11 | property var currentGame: modelData 12 | property bool wideHead: false 13 | property var backColor: settings["light"] ? "#EEEEEE" : "#181818" 14 | 15 | width: parent.width 16 | height: parent.height 17 | 18 | // Imageless backdrop 19 | Text { 20 | id: gameItemText 21 | 22 | anchors.fill: parent 23 | 24 | horizontalAlignment: Text.AlignHCenter 25 | verticalAlignment: Text.AlignVCenter 26 | 27 | text: currentGame.title 28 | wrapMode: Text.Wrap 29 | 30 | // Max gamesRows can be is 5, i've found 5 / rows to work well for scaling 31 | font.pixelSize: vpx(8) * (5 / settings["gamesRows"]) 32 | font.family: gilroyLight.name 33 | font.bold: true 34 | 35 | color: colors["text"] 36 | 37 | Rectangle { 38 | id: gameItemTextBack 39 | anchors.fill: parent 40 | z: parent.z - 1 41 | 42 | color: colors["plainSetting"] 43 | radius: settings["roundedGames"] ? height / roundedGamesRadiusFactor : 0 44 | 45 | LinearGradient { 46 | id: gameItemTextBackGradient 47 | source: parent 48 | anchors.fill: parent 49 | start: Qt.point(0, 0) 50 | end: Qt.point(0, parent.height) 51 | gradient: Gradient { 52 | GradientStop { position: 0.0; color: "transparent" } 53 | GradientStop { position: 1.0; color: colors["giGradient"] } 54 | } 55 | } 56 | } 57 | } 58 | 59 | // The image itself 60 | Image { 61 | id: gameItemImage 62 | width: parent.width 63 | height: parent.height 64 | 65 | z: gameItemText.z + 1 66 | 67 | anchors.centerIn: parent 68 | fillMode: Image.PreserveAspectCrop 69 | visible: false 70 | 71 | asynchronous: true 72 | 73 | source: (settings["wide"] || (wideHead && index == 0)) ? (currentGame.assets.steam || currentGame.assets.screenshot || currentGame.assets.background || currentGame.assets.banner || currentGame.assets.boxFront || currentGame.assets.marquee || currentGame.assets.poster) : (boxArt(currentGame)) 74 | 75 | // For Steam games that lack portrait mode art 76 | onStatusChanged: { 77 | if (status == Image.Error) { 78 | // The funny is gone 79 | console.log("No Steam Game art Found.") 80 | gameItemImage.source = currentGame.assets.boxFront; 81 | } 82 | } 83 | 84 | // The background for wide header 85 | Rectangle { 86 | id: wideHeadBG 87 | width: parent.width 88 | height: parent.height * .2 89 | 90 | anchors.right: parent.right 91 | anchors.bottom: parent.bottom 92 | 93 | visible: (settings["wide"] || (wideHead && index == 0)) && !settings["disableWideHeader"] 94 | 95 | color: "#60000000" 96 | } 97 | 98 | VideoPlayer { 99 | id: videoPlayer 100 | game: currentGame 101 | 102 | width: parent.width 103 | height: parent.height 104 | anchors.centerIn: parent 105 | 106 | playing: settings["videoPlayback"] && doubleFocus && !isFeed 107 | noSound: settings["nosfx"] 108 | } 109 | } 110 | 111 | OpacityMask { 112 | id: gameItemImageRounded 113 | anchors.fill: gameItemImage 114 | source: gameItemImage 115 | maskSource: gameItemMask 116 | } 117 | 118 | 119 | 120 | ShaderEffectSource{ 121 | id: shaderSource 122 | sourceItem: gameItemImageRounded 123 | width: gameItemImage.width 124 | height: gameItemImage.height * .2 125 | 126 | anchors{ 127 | right: gameItemImage.right 128 | bottom: gameItemImage.bottom 129 | } 130 | 131 | sourceRect: Qt.rect(x,y, width, height) 132 | } 133 | 134 | GaussianBlur { 135 | id: gameItemImageBlur 136 | anchors.fill: shaderSource 137 | source: shaderSource 138 | radius: 32 139 | samples: 30 140 | 141 | visible: false //wide || (wideHead && index == 0) 142 | } 143 | 144 | OpacityMask { 145 | anchors.fill: gameItemImageBlur 146 | source: gameItemImageBlur 147 | maskSource: gameItemBlurMask 148 | visible: (settings["wide"] || (wideHead && index == 0)) && !settings["disableWideHeader"] 149 | } 150 | 151 | Rectangle { 152 | id: wideViewTextAnchor 153 | visible: false 154 | width: parent.width 155 | height: parent.height * .2 156 | 157 | anchors.bottom: parent.bottom 158 | } 159 | 160 | // Wide header text 161 | Text { 162 | id: wideViewText 163 | 164 | visible: (settings["wide"] || (wideHead && index == 0)) && !settings["disableWideHeader"] 165 | 166 | anchors.verticalCenter: wideViewTextAnchor.verticalCenter 167 | anchors.left: wideViewTextAnchor.left 168 | anchors.leftMargin: parent.width * 0.05 169 | 170 | width: settings["showWideTimes"] ? parent.width * .75 : parent.width * .9 171 | height: parent.height * .2 172 | 173 | horizontalAlignment: Text.AlignLeft 174 | verticalAlignment: Text.AlignVCenter 175 | 176 | text: currentGame.title 177 | elide: Text.ElideRight 178 | 179 | // The wide header is always present in the home screen at the same size; 180 | // to accomodate smaller wide games, scale based on height. 181 | font.pixelSize: height / 3.5 182 | font.family: gilroyLight.name 183 | font.bold: true 184 | 185 | color: "white" 186 | z: wideHeadBG.z + 1 187 | } 188 | 189 | Text { 190 | id: gameTimeText 191 | 192 | visible: (settings["wide"] || (wideHead && index == 0)) && !settings["disableWideHeader"] && settings["showWideTimes"] 193 | 194 | anchors.verticalCenter: wideViewTextAnchor.verticalCenter 195 | anchors.right: wideViewTextAnchor.right 196 | anchors.rightMargin: parent.width * 0.05 197 | 198 | width: parent.width * .15 199 | height: parent.height * .2 200 | 201 | horizontalAlignment: Text.AlignRight 202 | verticalAlignment: Text.AlignVCenter 203 | 204 | text: '' + icons.clock + ' ' + formattedPlaytime(playTime) + '' 205 | 206 | font.pixelSize: height / 3.5 207 | font.family: gilroyLight.name 208 | 209 | color: "white" 210 | z: wideHeadBG.z + 1 211 | 212 | function formattedPlaytime(playtime) { 213 | if (playtime === 0) { 214 | return loc.playtime_never 215 | } else if (playtime < 60) { 216 | return playtime + loc.playtime_seconds 217 | } else if (playtime < 3600) { 218 | return Math.floor(playtime / 60) + loc.playtime_minutes 219 | } else { 220 | return Math.floor(playtime / 3600) + loc.playtime_hours 221 | } 222 | } 223 | } 224 | 225 | 226 | 227 | // Favorite Image 228 | Item { 229 | id: favImgItem 230 | width: height 231 | height: parent.height * .15 232 | anchors.top: parent.top 233 | anchors.topMargin: parent.height * .025 234 | anchors.right: parent.right 235 | anchors.rightMargin: parent.height * .025 236 | z: parent.z + 5 237 | visible: currentGame.favorite 238 | Behavior on y { 239 | SmoothedAnimation { velocity: animVel } 240 | } 241 | Text { 242 | text: icons.star 243 | anchors.centerIn: parent 244 | font { 245 | family: icons.name; 246 | pixelSize: parent.height * .6 247 | } 248 | color: colors["bottomIcons"] 249 | } 250 | } 251 | 252 | // Drop shadow for the item 253 | DropShadow { 254 | width: parent.width 255 | height: parent.height 256 | 257 | source: gameItemTextBack 258 | 259 | anchors.centerIn: parent 260 | 261 | //visible: !plainBG 262 | opacity: giShadowOp 263 | 264 | radius: giShadowRad 265 | samples: giShadowRad * 2 + 1 266 | z: gameItemTextBack.z - 1 267 | } 268 | 269 | // Drop shadow for the favorite star 270 | DropShadow { 271 | source: favImgItem 272 | anchors.fill: favImgItem 273 | 274 | visible: favImgItem.visible 275 | spread: 0.35 276 | 277 | radius: 16 278 | samples: 17 279 | z: favImgItem.z - 1 280 | } 281 | 282 | 283 | 284 | Rectangle { 285 | id: gameItemMask 286 | anchors.fill: parent 287 | visible: false 288 | 289 | radius: settings["roundedGames"] ? height / roundedGamesRadiusFactor : 0 290 | } 291 | 292 | Rectangle { 293 | id: gameItemBlurMask 294 | anchors.fill: shaderSource 295 | visible: false 296 | 297 | radius: settings["roundedGames"] ? height / roundedGamesRadiusFactor / .2 : 0 298 | 299 | Rectangle { 300 | width: parent.width 301 | height: parent.height / 2 302 | 303 | anchors.top: parent.top 304 | } 305 | } 306 | 307 | 308 | // The following code used to get portrait art for steam games is from shinretro by TigraTT-Driver. 309 | 310 | // Box art 311 | function steamAppID (gameData) { 312 | var str = gameData.assets.boxFront.split("header"); 313 | return str[0]; 314 | } 315 | 316 | function steamBoxFront(gameData) { 317 | return steamAppID(gameData) + "/library_600x900_2x.jpg" 318 | } 319 | 320 | 321 | function boxArt(data, failed=false) { 322 | if (data != null) { 323 | if (data.assets.boxFront.includes("header.jpg")) { 324 | if (failed) { 325 | return data.assets.boxFront; 326 | } else { 327 | return steamBoxFront(data); 328 | } 329 | } 330 | else { 331 | if (data.assets.poster != "") 332 | return data.assets.poster; 333 | else if (data.assets.boxFront != "") 334 | return data.assets.boxFront; 335 | else if (data.assets.banner != "") 336 | return data.assets.banner; 337 | else if (data.assets.tile != "") 338 | return data.assets.tile; 339 | else if (data.assets.cartridge != "") 340 | return data.assets.cartridge; 341 | else if (data.assets.logo != "") 342 | return data.assets.logo; 343 | } 344 | } 345 | return ""; 346 | } 347 | } 348 | -------------------------------------------------------------------------------- /GameItems/VideoPlayer.qml: -------------------------------------------------------------------------------- 1 | import QtQuick 2.15 2 | import QtGraphicalEffects 1.12 3 | import QtMultimedia 5.15 4 | 5 | Item { 6 | id: root 7 | property var game 8 | property bool playing 9 | property bool noSound 10 | 11 | onGameChanged: { 12 | videoPreviewLoader.sourceComponent = undefined; 13 | videoDelay.restart(); 14 | } 15 | 16 | onPlayingChanged: { 17 | videoPreviewLoader.sourceComponent = undefined; 18 | videoDelay.restart(); 19 | } 20 | 21 | // Timer to show the video 22 | Timer { 23 | id: videoDelay 24 | 25 | interval: 600 26 | onTriggered: { 27 | if (playing && game && game.assets.videos.length) { 28 | videoPreviewLoader.sourceComponent = videoPreviewWrapper; 29 | } 30 | } 31 | } 32 | 33 | Component { 34 | id: videoPreviewWrapper 35 | 36 | Video { 37 | id: videocomponent 38 | 39 | anchors.fill: parent 40 | source: game.assets.videoList.length ? game.assets.videoList[0] : "" 41 | fillMode: VideoOutput.PreserveAspectCrop 42 | muted: noSound 43 | loops: MediaPlayer.Infinite 44 | autoPlay: true 45 | visible: game.assets.videoList.length 46 | } 47 | } 48 | 49 | Item { 50 | id: videocontainer 51 | 52 | anchors.fill: parent 53 | 54 | Loader { 55 | id: videoPreviewLoader 56 | asynchronous: true 57 | anchors { fill: parent } 58 | } 59 | } 60 | 61 | } -------------------------------------------------------------------------------- /Localization.qml: -------------------------------------------------------------------------------- 1 | import QtQuick 2.8 2 | 3 | /* 4 | 5 | TRANSLATION CREDITS: 6 | 7 | Fr75s: English (EN) 8 | 9 | TigraTT-Driver: German (DE) 10 | 11 | */ 12 | 13 | Item { 14 | visible: false 15 | 16 | // Localization Chart 17 | 18 | /* Simply insert another language (e.g. "es") as a code and copy all the keys from the "en" object into your object like so: 19 | * "es": { 20 | * home_recent: "...", 21 | * home_favorite: "...", 22 | * ... 23 | * } 24 | */ 25 | 26 | /* Translations are welcome: Simply create a pull request on github or message me on discord (Francisco75s#0331) or matrix (@fr75s:matrix.org) to let me know if you have a good translation, and I will add it to the theme. 27 | * 28 | * TRANSLATION NOTE: If you've previously contributed, please add any translations to any fields labeled [], as these indicate new text that need to be translated. 29 | * 30 | * See more in the Translation section of MODIFICATIONS.md 31 | */ 32 | 33 | property var localization: { 34 | "en": { 35 | home_recent: "Recent Games", 36 | home_favorite: "Favorite Games", 37 | all_search: "Search", 38 | all_feed: "Feed", 39 | all_feed_instructions: "Press L2 at any time to stop.", 40 | collections_title: "Collections", 41 | settings_title: "Settings", 42 | settings_light_mode: "Light Mode", 43 | settings_plain_bg: "Plain Background", 44 | settings_disable_buttons: "Disable Button Prompts", 45 | settings_button_scheme: "Button Prompt Style", 46 | settings_rounded_corners: "Rounded Games", 47 | settings_center_titles: "Center Titles", 48 | settings_enable_clockbar: "Enable Clock", 49 | settings_wide_games: "Wide Games View", 50 | settings_wide_games_info: "Increases the width of each game, changing to art that fits closer to the wider ratio.", 51 | settings_diff_aspect: "Change Aspect Ratios", 52 | settings_diff_aspect_info: "Changes each game's aspect ratios from 2:3 and 92:43 to 3:4 and 16:9", 53 | settings_show_wide_times: "Show Playtime (Wide View)", 54 | settings_force_recent_narrow: "Override Wide 1st Recent Game", 55 | settings_force_recent_narrow_info: "Makes the first game in the \"Recent Games\" section portrait, similar to other games when Wide Games View is disabled.", 56 | settings_games_grid_rows: "Number of Rows per Screen for Games", 57 | settings_collection_grid_rows: "Number of Rows per Screen for Collections", 58 | settings_enable_touchnav: "Enable Touch Navigation Icons", 59 | settings_enable_touchnav_info: "Adds arrows on the top right of certain game grids to allow you to go back if you're using a touch device or mouse.", 60 | settings_more_recents: "More Recent Games Shown", 61 | settings_more_recents_info: "Increases the number of games on the Recent Games list from 8 to 16.", 62 | settings_force_home: "Force to Home on Return", 63 | settings_force_home_info: "Makes you go to the home page upon closing a game, rather than returning to where you were.", 64 | settings_limit_search: "Limit Search to Starting Characters", 65 | settings_limit_search_info: "Makes it so that searches search for games that start with the text searched, not games that contain the text searched (both in their titles)", 66 | settings_search_mode: "Search Mode", 67 | settings_search_mode_info: "Changes how games are found using the given search prompt in the search tab. Refer to EXTRAINFO.md in the theme folder for more info.", 68 | settings_search_mode_regular: "regular", 69 | settings_search_mode_limited: "limited", 70 | settings_search_mode_fuzzy: "fuzzy", 71 | settings_search_mode_raw: "raw", 72 | settings_enlarge_bar: "Change Bar Size", 73 | settings_bar_size_tiny: "tiny", 74 | settings_bar_size_small: "small", 75 | settings_bar_size_medium: "medium", 76 | settings_bar_size_large: "large", 77 | settings_classic_colors: "Use Classic Colorscheme", 78 | settings_classic_colors_info: "Reverts the colors of the UI back to the colors used in Library prior to version 1.2.0.", 79 | settings_disable_wide_header: "Disable Wide Game Titles", 80 | settings_quiet_sounds: "Quiet Sound Effects", 81 | settings_mute_sounds: "Mute Audio", 82 | settings_video_playback: "Video Playback", 83 | settings_blur_collects: "Blur Collection Images", 84 | settings_change_localization: "Change Language", 85 | settings_change_bg: "Change Background", 86 | settings_24h_clock: "24-hour clock", 87 | 88 | settings_header_appearance: "Appearance", 89 | settings_header_behavior: "Behavior", 90 | settings_header_av: "Audio & Video", 91 | settings_header_interface: "Interface", 92 | settings_header_localization: "Localization", 93 | 94 | playtime_never: "Never", 95 | playtime_seconds: "s", 96 | playtime_minutes: "m", 97 | playtime_hours: "h", 98 | 99 | bottomBar_changePage: "Change Page", 100 | bottomBar_aSelect: "Select", 101 | bottomBar_aPlay: "Play", 102 | bottomBar_aSetting: "Change Setting", 103 | bottomBar_bKeyboard: "Hide Keyboard", 104 | bottomBar_bExit: "Exit Collection", 105 | bottomBar_xKeyboard: "Keyboard / Backspace", 106 | bottomBar_xNext: "Next Section", 107 | bottomBar_yFavorite: "Favorite", 108 | bottomBar_yNext: "Next", 109 | bottomBar_yKeyboard: "Favorite / Space", 110 | bottomBar_yInfo: "Show Extra Info" 111 | 112 | }, 113 | "de": { 114 | home_recent: "Zuletzt gespielt", 115 | home_favorite: "Lieblings Spiele", 116 | all_search: "Suche", 117 | all_feed: "Feed", 118 | all_feed_instructions: "Drücke L2 um Spiele-Feed-Modus zu verlassen.", 119 | collections_title: "Sammlungen", 120 | settings_title: "Einstellungen", 121 | settings_light_mode: "Heller-Modus", 122 | settings_plain_bg: "Einfarbiger Hintergrund", 123 | settings_disable_buttons: "Eingabehilfen deaktivieren", 124 | settings_button_scheme: "Design der Eingabehilfe", 125 | settings_rounded_corners: "Abgerundete Spiele", 126 | settings_center_titles: "Überschriften zentrieren", 127 | settings_enable_clockbar: "Uhr anzeigen", 128 | settings_wide_games: "Breite Spiele-Ansicht", 129 | settings_wide_games_info: "Erhöht die Breite jedes Spiels und wechselt zu Grafiken, die besser in das breitere Verhältnis passen.", 130 | settings_diff_aspect: "[]", 131 | settings_diff_aspect_info: "[]", 132 | settings_show_wide_times: "[]", 133 | settings_force_recent_narrow: "[]", 134 | settings_force_recent_narrow_info: "[]", 135 | settings_games_grid_rows: "Anzahl der Reihen für Spielelisten", 136 | settings_collection_grid_rows: "Anzahl der Reihen für die Sammlungen-Übersicht", 137 | settings_enable_touchnav: "Touch-Navigationssymbole aktivieren", 138 | settings_enable_touchnav_info: "Fügt Pfeile oben rechts in bestimmten Spielrastern hinzu, damit man zurückgehen kann, wenn man ein Touch-Gerät oder eine Maus benutzt.", 139 | settings_more_recents: "Zeige mehr zuletzt gespielte Spiele", 140 | settings_more_recents_info: "Erhöht die Anzahl der Spiele in der Liste der zuletzt gespielten Spiele von 8 auf 16.", 141 | settings_force_home: "[]", 142 | settings_force_home_info: "[]", 143 | settings_limit_search: "Suche auf Textanfang beschränken", 144 | settings_limit_search_info: "Sorgt dafür, dass nach Spielen gesucht wird, die mit dem gesuchten Text beginnen, und nicht nach Spielen, die den gesuchten Text enthalten (beide in ihren Titeln)", 145 | settings_search_mode: "[]", 146 | settings_search_mode_info: "[]", 147 | settings_search_mode_regular: "[]", 148 | settings_search_mode_limited: "[]", 149 | settings_search_mode_fuzzy: "[]", 150 | settings_search_mode_raw: "[]", 151 | settings_enlarge_bar: "Leistengröße", 152 | settings_bar_size_tiny: "winzig", 153 | settings_bar_size_small: "klein", 154 | settings_bar_size_medium: "mittel", 155 | settings_bar_size_large: "groß", 156 | settings_classic_colors: "Verwende klassisches Farbschema", 157 | settings_classic_colors_info: "Benutzeroberfläche verwendet Farbschemas, die in Library vor Version 1.2.0 verwendet wurden", 158 | settings_disable_wide_header: "Deaktiviere Spieletitel-Banner bei der breiten Spiele-Ansicht", 159 | settings_quiet_sounds: "Leisere Soundeffekte", 160 | settings_mute_sounds: "Soundeffekte stummschalten", 161 | settings_video_playback: "Videowiedergabe", 162 | settings_blur_collects: "Unscharfe Sammlungsbilder", 163 | settings_change_localization: "Anzeigesprache", 164 | settings_change_bg: "Hintergrund ändern", 165 | settings_24h_clock: "24-Stunden Uhr", 166 | 167 | settings_header_appearance: "Erscheinungsbild", 168 | settings_header_behavior: "Verhalten", 169 | settings_header_av: "Audio & Video", 170 | settings_header_interface: "Oberfläche", 171 | settings_header_localization: "Lokalisierung", 172 | 173 | playtime_never: "[]", 174 | playtime_seconds: "s", 175 | playtime_minutes: "m", 176 | playtime_hours: "h", 177 | 178 | bottomBar_changePage: "Seite wechseln", 179 | bottomBar_aSelect: "Auswählen", 180 | bottomBar_aPlay: "Spielen", 181 | bottomBar_aSetting: "Einstellung ändern", 182 | bottomBar_bKeyboard: "verstecke Tastatur", 183 | bottomBar_bExit: "Sammlung verlassen", 184 | bottomBar_xKeyboard: "Tastatur / Rücktaste", 185 | bottomBar_xNext: "Nächster Abschnitt", 186 | bottomBar_yFavorite: "Favorit", 187 | bottomBar_yNext: "Nächstes", 188 | bottomBar_yKeyboard: "Favorit / Leertaste", 189 | bottomBar_yInfo: "Mehr Infos" 190 | }, 191 | "ja": { 192 | home_recent: "最近プレイしたゲーム", 193 | home_favorite: "お気に入りのゲーム", 194 | all_search: "検索", 195 | all_feed: "フィード", 196 | all_feed_instructions: "停止するには L2 を押してください。", 197 | collections_title: "コレクション", 198 | settings_title: "設定", 199 | settings_light_mode: "ライトモード", 200 | settings_plain_bg: "シンプル背景", 201 | settings_disable_buttons: "ボタンガイドを無効にする", 202 | settings_button_scheme: "ボタンガイドのスタイル", 203 | settings_rounded_corners: "サムネイルを角丸にする", 204 | settings_center_titles: "タイトルを中央寄せ", 205 | settings_enable_clockbar: "時計を有効にする", 206 | settings_wide_games: "ワイドゲームビュー", 207 | settings_wide_games_info: "各ゲームの幅を増やし、ワイド比率に合うようにアートワークの種類を変更します。", 208 | settings_diff_aspect: "[]", 209 | settings_diff_aspect_info: "[]", 210 | settings_show_wide_times: "プレイ時間を表示 (ワイドビュー)", 211 | settings_force_recent_narrow: "最近プレイしたゲームの 1 件目を縦長にする", 212 | settings_force_recent_narrow_info: "ワイドゲームビューが無効の場合、「最近プレイしたゲーム」に表示される 1 件目のゲームを他のゲームと同様に縦長にします。", 213 | settings_games_grid_rows: "画面に表示する行数 (ゲーム)", 214 | settings_collection_grid_rows: "画面に表示する行数 (コレクション)", 215 | settings_enable_touchnav: "タッチナビゲーションアイコンを有効にする", 216 | settings_enable_touchnav_info: "特定の画面の右上に矢印を追加し、タッチデバイスやマウスを使用している場合に戻ることができるようにします。", 217 | settings_more_recents: "最近プレイしたゲームの表示数を増やす", 218 | settings_more_recents_info: "最近プレイしたゲームの一覧に表示されるゲームの件数を 8 から 16 に増やします。", 219 | settings_force_home: "[]", 220 | settings_force_home_info: "[]", 221 | settings_limit_search: "前方一致検索", 222 | settings_limit_search_info: "検索されたテキストを含むゲームではなく、検索されたテキストで始まるゲームを検索するようにします。", 223 | settings_search_mode: "[]", 224 | settings_search_mode_info: "[]", 225 | settings_search_mode_regular: "[]", 226 | settings_search_mode_limited: "[]", 227 | settings_search_mode_fuzzy: "[]", 228 | settings_search_mode_raw: "[]", 229 | settings_enlarge_bar: "バーの大きさを変更", 230 | settings_bar_size_tiny: "極小", 231 | settings_bar_size_small: "小", 232 | settings_bar_size_medium: "中", 233 | settings_bar_size_large: "大", 234 | settings_classic_colors: "古いカラースキームを使用する", 235 | settings_classic_colors_info: "UI 配色をバージョン 1.2.0 以前の Library で使用されていたものに戻します。", 236 | settings_disable_wide_header: "ワイドビューでタイトルを表示しない", 237 | settings_quiet_sounds: "効果音の音量を下げる", 238 | settings_mute_sounds: "オーディオを消音", 239 | settings_video_playback: "ビデオを再生する", 240 | settings_blur_collects: "コレクション画像をぼかす", 241 | settings_change_localization: "言語を変更", 242 | settings_change_bg: "背景を変更", 243 | settings_24h_clock: "24時間時計", 244 | 245 | settings_header_appearance: "外観", 246 | settings_header_behavior: "動作", 247 | settings_header_av: "オーディオ & ビデオ", 248 | settings_header_interface: "インターフェース", 249 | settings_header_localization: "言語", 250 | 251 | playtime_never: "未プレイ", 252 | playtime_seconds: "秒", 253 | playtime_minutes: "分", 254 | playtime_hours: "時間", 255 | 256 | bottomBar_changePage: "ページを変更", 257 | bottomBar_aSelect: "選択", 258 | bottomBar_aPlay: "プレイ", 259 | bottomBar_aSetting: "設定を変更", 260 | bottomBar_bKeyboard: "キーボードを隠す", 261 | bottomBar_bExit: "コレクションから戻る", 262 | bottomBar_xKeyboard: "キーボード / バックスペース", 263 | bottomBar_xNext: "次のセクション", 264 | bottomBar_yFavorite: "お気に入り", 265 | bottomBar_yNext: "次へ", 266 | bottomBar_yKeyboard: "お気に入り / スペース", 267 | bottomBar_yInfo: "追加情報を表示" 268 | 269 | } 270 | } 271 | 272 | function getLocalization(lang) { 273 | return localization[lang] 274 | } 275 | 276 | function getLangs() { 277 | return Object.keys(localization) 278 | } 279 | } 280 | -------------------------------------------------------------------------------- /MODIFICATIONS.md: -------------------------------------------------------------------------------- 1 | # Library Modifications 2 | 3 | ## Table of Contents 4 | 5 | 1. [Necessary Information](#some-information) 6 | 2. [Quick Modifications](#quick-modifications) 7 | - [Custom Color Schemes (1.2.0+)](#custom-color-schemes) 8 | - [Extra Collections](#extra-collections) 9 | 3. [Adding Translations](#translations) 10 | 11 | ## Some Information 12 | 13 | You may want to refer to the QML documentation for common types. QML has many different types, whose properties are thoroughly documented. Common QML types [can be found here](https://doc.qt.io/qt-5/qtquick-qmlmodule.html) 14 | 15 | ## Quick Modifications 16 | 17 | Here are some quick modifications you can do on Library. These don't teach you much, but they add functionality that isn't included by default or in the settings. 18 | 19 | ### Center Titles 20 | 21 | To center game titles, it is incredibly easy. The functionality is already there, though it is disabled by default. 22 | 23 | Go into theme.qml, and find the variable `centerTitles` (it should be under all the settings). Then, you would simply change it to true like so: 24 | 25 | ``` 26 | property bool centerTitles: true 27 | ``` 28 | 29 | This is all that is needed to make the Collections page top menu become wide in wide mode. One could get wide images if they wish, but to implement these, it would take a bit more effort in GICusart.qml, which I will not cover here. 30 |

31 | 32 | ### Custom Color Schemes 33 | 34 | Creating custom color schemes for this theme can be done by going into theme.qml and modifying the colorschemes variable. 35 | 36 | To do this, first open up theme.qml. You should then navigate to a big object with lots of strings, looking like so: 37 | 38 | ``` 39 | property var colorschemes: { 40 | "polar": { 41 | "light": { 42 | "plainBG": "#F2F6FF", 43 | ... 44 | ``` 45 | 46 | This is your color scheme variable, and is where you will define color schemes. I recommend adding something like so: 47 | 48 | ``` 49 | }, 50 | "mycolorscheme": { 51 | "light": { 52 | ... 53 | }, 54 | "dark": { 55 | ... 56 | } 57 | } 58 | ``` 59 | 60 | After making this, add all the colors in. You can find the names of each color by looking at either the polar or classic color schemes, which are there by default and contain color names like "accent" and "text." Use the same style as the other color schemes, replacing the hex codes or color names with whatever colors you want. 61 | 62 | Once you finish your colorscheme, simply replace the line `property var colors: ...` with the following: 63 | 64 | ``` 65 | property var colors: light ? colorschemes["mycolorscheme"]["light"] : colorschemes["mycolorscheme"]["dark"] 66 | ``` 67 | 68 | Now you have a custom color scheme for use with Library. 69 |

70 | 71 | ### Extra Collections 72 | 73 | You may see a few extra collections when browsing through the collection images. Here is how to do a few of them. 74 | 75 | **Windows Store Games**
76 | Surprisingly enough, Windows store games can be used and run well in Pegasus, better than steam games even. Using the following method, you will be able to run windows store games on Pegasus. 77 | 78 | 1. Install UWPHook
79 | UWPHook is a tool which enables you to put windows store games on steam, however, it also enables you to launch windows store games using relatively simple commands on the command line. [The link to the project can be found here.](https://briano.dev/UWPHook/) 80 | 81 | 2. Find out your game's code
82 | Finding out the code of your game is the hardest part. This will require you to go into your AppData folder, which is typically hidden in your user folder. Go to %APPDATA%/Local/Packages, and you will find folders containing the contents of windows store applications, but only the names are needed here. Copy the names of the applications you wish to use: you can typically discern your app from others by looking for the developer's name. Copy the names of the folders containing the apps you would like to launch, and save them for later. 83 | 84 | 3. Creating blank files
85 | To go around Pegasus's requirement for 1 file per game, we will create several files. In the same place you wish to put your metadata.pegasus.txt, create one blank file for each package name you got in step 2. Rename these to `[PACKAGE_NAME].txt` 86 | 87 | 4. Creating metadata.pegasus.txt
88 | Once this is done, metadata.pegasus.txt is relatively simple. With a default UWPHook install location: 89 | ``` 90 | collection: Windows Store 91 | shortname: winuwp 92 | launch: "C:/Program Files (x86)/Briano/UWPHook/UWPHook.exe" "{file.basename}!App" 93 | ``` 94 | 95 | Then, you would define games with: 96 | ``` 97 | game: [GAME_NAME] 98 | file: ./[PACKAGE_NAME].txt 99 | ... 100 | ``` 101 | 102 | This is all that is needed to run windows store games on pegasus. 103 | 104 | 105 | 106 | **Pico-8**
107 | Pico-8 through pegasus frontend is easy and simple to do if you have the desktop application. Once you do so, creating a metadata.pegasus.txt file is easy: 108 | 109 | ``` 110 | collection: Pico-8 111 | shortname: pico8 112 | ... 113 | launch: [PATH OF PICO-8 EXECUTABLE] -run {file.path} 114 | ... 115 | ``` 116 | 117 | This is good if Pico-8 is installed portably on your system; if not, simply use pico-8 rather than the full path. 118 | 119 | **Tic-80**
120 | Tic-80 comes as a libretro core, making it easy to use with retroarch. While retroarch may differ per system, using a metadata.pegasus.txt which links to the tic-80 core would allow you to run tic-80 games in retroarch. 121 | 122 | 123 | ## Adding Translations 124 | 125 | Translating this theme is done through the Localization.qml file. 126 | 127 | First, open Localization.qml and navigate to the localization property, which should look like so: 128 | 129 | ``` 130 | property var localization: { 131 | "en": { 132 | home_recent: "Recent Games", 133 | home_favorite: "Favorite Games", 134 | ... 135 | } 136 | ... 137 | } 138 | ``` 139 | 140 | Pay attention to the "en" object within localization. This is what you should copy to translate the theme. Create a new object with the same keys as `"en"`, then replace the English strings with those of your desired language. Afterwards, rename the `"en"` copy to the 2 letter code for your language, e.g. `"es"` for Spanish. Your localization object should now look like so (using "es"/Spanish as an example): 141 | 142 | ``` 143 | property var localization: { 144 | "en": { 145 | home_recent: "Recent Games", 146 | home_favorite: "Favorite Games", 147 | ... 148 | }, 149 | "es": { 150 | home_recent: "Juegos Recientes", 151 | home_favorite: "Juegos Favoritos", 152 | ... 153 | } 154 | ... 155 | } 156 | ``` 157 | 158 | If your object is written properly, you are done, as Library handles the rest when it comes to using your strings and changing languages. To test your localization, change your language to the one you added by going to the Settings page and clicking the "Change Language" option, located at the bottom of the page. 159 | 160 | Afterwards, you probably want to add this to the theme officially to let others access your translation. Simply add a pull request to the github page (you can search a tutorial for that online) or message me on Discord (Francisco75s#0331; if you prefer matrix @fr75s:matrix.org), and I will happily add your translation. 161 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | ## A Clean, Modern, Bigscreen Interface for Pegasus Frontend 5 | 6 | If you are looking to use this theme, [Check out the website for this theme here.](https://fr75s.github.io/library/assets/SAFELY_REMOVABLE/website/main.html) 7 | 8 | Library is a clean, modern interface for [Pegasus Frontend](http://pegasus-frontend.org) that aims to provide a theme which doesn't emphasize text. Inspired partly by the Steam Deck's UI, this interface focuses more on providing the box art in organized categories, with little textual metadata. 9 | 10 | *** 11 | 12 | ## Installation 13 | 14 | [Full installation instructions are available here.](https://fr75s.github.io/library/assets/SAFELY_REMOVABLE/website/install.html) 15 | 16 | To install this theme, first download this repository (either through `git clone https://github.com/Fr75s/library.git` or through downloading this zip), then move (and extract if you downloaded the zip) to [your themes folder.](https://pegasus-frontend.org/docs/user-guide/installing-themes/) Finally, remove the SAFELY_REMOVABLE folder located within this theme's folder under assets. 17 | 18 | *** 19 | 20 | ## Special Thanks 21 | 22 | I used other themes as references while building Library. These themes are listed below. 23 | 24 | - https://github.com/valsou/neoretro: The framework I built this theme off of, used for the separate page file system and Colcon.qml. 25 | - https://github.com/TigraTT-Driver/shinretro: A theme which provided the functionality for portrait-style steam game box art and more. I didn't find out about this theme until Library was mostly complete. 26 | - https://github.com/PlayingKarrde/clearOS: A theme providing part of the search functionality of the theme. 27 | 28 | I would also like to thank the following people: 29 | 30 | [TigraTT-Driver](https://github.com/TigraTT-Driver/), who has contributed several new features to Library and who has provided the German translation. 31 | 32 | [waitingmoon](https://github.com/waitingmoon), who has provided the Japanese translation. 33 | 34 | *** 35 | 36 | ## Issues? 37 | 38 | If you find any issues or want to let me know of anything, feel free to open up an issue in this project. You may also want to check out the [Modifications Guide](https://github.com/Fr75s/library/blob/main/MODIFICATIONS.md) and see if I have placed a fix there. If not, then, once again, feel free to open up an issue, and I will fix it. 39 | 40 | If you know a language other than English, I encourage you to translate this theme. All relevant info is in the [Translation Section](https://github.com/Fr75s/library/blob/main/MODIFICATIONS.md) of the modifications guide and in Localization.qml. 41 | 42 | *** 43 | 44 | ## Screenshots 45 | 46 | The following shows some screenshots of the theme. All screenshots can be found on [The Pegasus Theme Gallery](https://pegasus-frontend.org/tools/themes/), or in [The SAFELY_REMOVABLE Directory.](https://github.com/Fr75s/library/tree/main/assets/SAFELY_REMOVABLE) 47 | 48 | ![The Home Screen (Default Theme)](./assets/SAFELY_REMOVABLE/screenshot_1.png) 49 | ![The Collections Screen (Modified Background)](./assets/SAFELY_REMOVABLE/screenshot_8.png) 50 | ![The Search Screen (Modified number of rows, games are in wide)](./assets/SAFELY_REMOVABLE/screenshot_7.png) 51 | ![The Settings Screen](./assets/SAFELY_REMOVABLE/screenshot_5.png) 52 | -------------------------------------------------------------------------------- /Theme/All.qml: -------------------------------------------------------------------------------- 1 | import QtQuick 2.15 2 | import QtMultimedia 5.15 3 | import QtQuick.Layouts 1.15 4 | import QtGraphicalEffects 1.15 5 | import QtQuick.Window 2.15 6 | 7 | import SortFilterProxyModel 0.2 8 | 9 | import "../GameItems" 10 | import "PegaKey" 11 | 12 | /* 13 | * 14 | * Note 15 | * This may be called all, but this has been revitalized to a search 16 | * 17 | */ 18 | 19 | FocusScope { 20 | id: search 21 | 22 | property bool feed: false 23 | property bool searching: false 24 | 25 | // Converts the text in searchInput to a regex pattern 26 | function searchInputConvert(inputText) { 27 | if (settings["searchMode"] === "raw") { 28 | return inputText; 29 | } else { 30 | const specialSymbols = ["^", "$", "\\", ".", "*", "+", "?", "(", ")", "[", "]", "{", "}", "|", "/"]; 31 | const capitals = /[A-Z]/g; 32 | 33 | if (settings["searchMode"] === "fuzzy") { 34 | let outputStr = ""; 35 | for (let i = 0; i < inputText.length; i++) { 36 | if (inputText[i].match(capitals)) { 37 | // Make next letter match require to start at next word 38 | outputStr += "\\b" + inputText[i]; 39 | } else if (specialSymbols.includes(inputText[i])) { 40 | // Escape special character 41 | outputStr += "\\" + inputText[i]; 42 | } else { 43 | outputStr += inputText[i]; 44 | } 45 | // Loose Matching 46 | outputStr += ".*"; 47 | } 48 | console.log(JSON.stringify(outputStr)); 49 | return outputStr; 50 | } else { 51 | // Escape special symbols 52 | let regexCleanText = inputText.split(""); 53 | for (let i = regexCleanText.length - 1; i >= 0; i--) { 54 | if (specialSymbols.includes(regexCleanText[i])) { 55 | regexCleanText.splice(i, 0, "\\"); 56 | } 57 | } 58 | let outputStr = ""; 59 | for (let i = 0; i < regexCleanText.length; i++) { 60 | outputStr += regexCleanText[i]; 61 | } 62 | 63 | // Add ^ to beginning of pattern if limited search 64 | if (settings["searchMode"] === "lim") { 65 | outputStr = "^" + outputStr; 66 | } 67 | return outputStr; 68 | } 69 | } 70 | } 71 | 72 | // Define Current Game 73 | SortFilterProxyModel { 74 | id: searchSort 75 | sourceModel: api.allGames 76 | 77 | // The searching functionality for the model 78 | filters: RegExpFilter { 79 | roleName: "title"; 80 | // Limited search matches ^[term] rather than [term] 81 | pattern: searchInputConvert(searchInput.text); 82 | enabled: searchInput.text != ""; 83 | caseSensitivity: Qt.CaseInsensitive; 84 | } 85 | } 86 | 87 | /* 88 | * Note: The bug pertaining to not being able to run or favorite games when searching was fixed 89 | * by changing searchSort.get(allView.currentIndex) to api.allGames.get(searchSort.mapToSource(allView.currentIndex)). 90 | * This fix is from clearOS. 91 | * 92 | */ 93 | 94 | // The current game 95 | property var currentGameIndex: { 96 | if (searchSort.count == 0 || searchSort.count == api.allGames.count) 97 | return allView.currentIndex; 98 | else 99 | return searchSort.mapToSource(allView.currentIndex); 100 | } 101 | property var current: { 102 | return api.allGames.get(currentGameIndex); 103 | } 104 | property var feedCurrent 105 | 106 | // 107 | // Layouts 108 | // 109 | 110 | // Title 111 | Text { 112 | id: allTitle 113 | width: parent.width * .9 114 | 115 | y: parent.height * 0.075 116 | 117 | text: feed ? loc.all_feed : loc.all_search 118 | color: colors["text"] 119 | 120 | // Alignment 121 | horizontalAlignment: Text.AlignLeft 122 | 123 | font.family: gilroyLight.name 124 | font.pixelSize: parent.height * .05 125 | 126 | anchors.left: parent.left 127 | anchors.leftMargin: parent.width * 0.05 128 | } 129 | 130 | 131 | 132 | // Search Background, to indicate it is a search field 133 | // (outside of searchInput to prevent bug where searchInput text is under the bg) 134 | Rectangle { 135 | id: searchInputBG 136 | 137 | width: searchInput.width + (searchInput.height * .5) 138 | height: searchInput.height * 1.2 139 | anchors.centerIn: searchInput 140 | 141 | radius: height * .25 142 | visible: !feed 143 | 144 | gradient: Gradient { 145 | orientation: Gradient.Horizontal 146 | GradientStop { position: 0.0; color: colors["plainSetting"] } 147 | GradientStop { position: 1.0; color: colors["plainBG"] } 148 | } 149 | 150 | // Highlight when searching 151 | Rectangle { 152 | anchors.fill: parent 153 | radius: parent.radius 154 | 155 | visible: (menu == 1) && !(allView.focus) 156 | 157 | border.color: colors["accent"] 158 | border.width: 2 159 | color: "transparent" 160 | } 161 | } 162 | 163 | DropShadow { 164 | anchors.fill: searchInputBG 165 | source: searchInputBG 166 | 167 | visible: !settings["plainBG"] && !feed 168 | opacity: giShadowOp 169 | 170 | radius: giShadowRad 171 | samples: giShadowRad * 2 + 1 172 | z: searchInputBG.z - 1 173 | } 174 | 175 | // Search text input, used for searching 176 | // Its text property is what is used for searching 177 | TextInput { 178 | id: searchInput 179 | width: parent.width * .6 180 | height: parent.height * .06 181 | 182 | visible: !feed 183 | focus: false 184 | 185 | y: parent.height * 0.075 186 | 187 | color: colors["text"] 188 | 189 | // Alignment 190 | horizontalAlignment: Text.AlignLeft 191 | verticalAlignment: Text.AlignVCenter 192 | 193 | font.family: gilroyLight.name 194 | font.pixelSize: parent.height * .05 195 | 196 | selectByMouse: true; 197 | 198 | anchors.right: parent.right 199 | anchors.rightMargin: parent.width * 0.05 200 | 201 | // Indicator for the word, used to show the end of the text 202 | Rectangle { 203 | width: 1 204 | height: parent.height 205 | 206 | anchors.left: parent.left 207 | anchors.leftMargin: parent.contentWidth 208 | 209 | visible: (menu == 1) && !(allView.focus) 210 | } 211 | 212 | // Click control, invokes keyboard 213 | MouseArea { 214 | anchors.fill: parent 215 | 216 | onClicked: { 217 | keys.invokeNoFocus(); 218 | parent.focus = true; 219 | searching = true; 220 | } 221 | } 222 | 223 | Keys.onEscapePressed: { 224 | keys.hide(); 225 | } 226 | 227 | Keys.onPressed: { 228 | if (event.isAutoRepeat) { 229 | return 230 | } 231 | 232 | if (api.keys.isAccept(event)) { 233 | event.accepted = true; 234 | keys.hide(); 235 | } 236 | } 237 | } 238 | 239 | /* The special keyboard implementation, instantiated here 240 | * This is the main way an actual implementation of this is shown. 241 | * The keyboard's functionality can be found by looking at the files in the PegaKey folder. 242 | * 243 | */ 244 | Keyboard { 245 | id: keys 246 | 247 | // Width and height are defined in the keyboard 248 | anchors.fill: parent 249 | z: 20 250 | 251 | kcolors: colors["keyboard"] 252 | 253 | sfxSource: ".././assets/audio/type.wav" 254 | quietSfx: settings["quiet"]; 255 | muteSfx: settings["nosfx"]; 256 | 257 | // Adds key to input, unless it's a backspace or clear 258 | onSendKey: { 259 | if (text == "bksp") { 260 | if (searchInput.text.length > 0) { 261 | searchInput.text = searchInput.text.substring(0, searchInput.text.length - 1) 262 | } 263 | } else if (text == "CLEAR") { 264 | searchInput.text = "" 265 | } else { 266 | searchInput.text = searchInput.text + text; 267 | searchInput.forceLayout() 268 | } 269 | } 270 | 271 | // Invoke provides more functionality in the keyboard itself. 272 | onInvoked: { 273 | searching = true; 274 | } 275 | 276 | // More functionality is in the keyboard itself. 277 | // It also focuses the game view. 278 | onDone: { 279 | searching = false; 280 | allView.focus = (menu == 1) && !searching; 281 | } 282 | } 283 | 284 | // All View 285 | // See all games or searched games 286 | GridView { 287 | id: allView 288 | width: settings["wide"] ? height * (2.14) : height * (2) 289 | height: settings["wide"] ? parent.height * 0.7 : parent.height * 0.75 //* (Math.ceil(api.allGames.count / 6)) 290 | 291 | // Rectangle { 292 | // anchors.fill: parent 293 | // opacity: 0.1 294 | // } 295 | 296 | anchors.top: parent.top 297 | anchors.topMargin: parent.height * .175 298 | anchors.horizontalCenter: parent.horizontalCenter 299 | 300 | visible: !feed 301 | 302 | // Grid 303 | cellWidth: getCellWidth(cellHeight, true)//settings["wide"] ? (cellHeight * (92/43)) : (cellHeight * (2/3)) 304 | cellHeight: height / settings["gamesRows"] 305 | 306 | // Sets the model to everything if the search is empty or contains all games 307 | model: (searchSort.count == 0 || searchSort.count == api.allGames.count) ? api.allGames : searchSort 308 | 309 | delegate: Item { 310 | readonly property bool isCurrentItem: GridView.isCurrentItem 311 | // Once again, double focus indicates this game is selected 312 | readonly property bool doubleFocus: allView.focus && isCurrentItem 313 | 314 | width: GridView.view.cellWidth 315 | height: GridView.view.cellHeight 316 | 317 | Item { 318 | anchors { 319 | fill: parent 320 | margins: (doubleFocus) ? 0 : vpx(10) 321 | } 322 | 323 | Behavior on anchors.margins { 324 | SmoothedAnimation { velocity: marginAnimVel } 325 | } 326 | 327 | GINormal { } 328 | 329 | /* 330 | Loader { 331 | anchors.fill: parent 332 | asynchronous: true 333 | sourceComponent: GINormal { } 334 | active: all.focus 335 | visible: status === Loader.Ready 336 | } 337 | */ 338 | 339 | // Click functionality 340 | MouseArea { 341 | anchors.fill: parent 342 | onClicked: { 343 | if (isCurrentItem) { 344 | launchGame(modelData) 345 | } 346 | else { 347 | allView.currentIndex = index 348 | if (!settings["nosfx"]) 349 | sNav.play(); 350 | if (searching) 351 | searching = false 352 | } 353 | } 354 | } 355 | } 356 | 357 | 358 | } 359 | 360 | clip: true 361 | focus: (menu == 1) && !searching 362 | 363 | // Invokes search if at top, otherwise move up 364 | Keys.onUpPressed: { 365 | if (!settings["nosfx"]) sNav.play(); 366 | if (settings["wide"]) { 367 | if (allView.currentIndex < settings["gamesRows"]) 368 | keys.invoke() 369 | } else { 370 | if (allView.currentIndex < (settings["gamesRows"] * 3)) 371 | keys.invoke() 372 | } 373 | if (!searching) 374 | moveCurrentIndexUp() 375 | } 376 | // Move down with special behavior 377 | Keys.onDownPressed: { 378 | if (!settings["nosfx"]) sNav.play(); 379 | 380 | // Go to last element if no element below on non-final row 381 | if (settings["wide"]) { 382 | if (allView.currentIndex + (settings["gamesRows"]) >= allView.count && allView.currentIndex % (settings["gamesRows"]) > (allView.count - 1) % (settings["gamesRows"])) 383 | allView.currentIndex = allView.count - 1; 384 | else { 385 | moveCurrentIndexDown(); 386 | } 387 | } else { 388 | if (allView.currentIndex + (settings["gamesRows"] * 3) >= allView.count && allView.currentIndex % (settings["gamesRows"] * 3) > (allView.count - 1) % (settings["gamesRows"] * 3)) 389 | allView.currentIndex = allView.count - 1; 390 | else { 391 | moveCurrentIndexDown(); 392 | } 393 | } 394 | } 395 | // Move left/right 396 | Keys.onLeftPressed: { if (!settings["nosfx"]) sNav.play(); moveCurrentIndexLeft() } 397 | Keys.onRightPressed: { if (!settings["nosfx"]) sNav.play(); moveCurrentIndexRight() } 398 | 399 | Keys.onPressed: { 400 | if (event.isAutoRepeat) { 401 | return 402 | } 403 | 404 | // Launch Game 405 | if (api.keys.isAccept(event)) { 406 | event.accepted = true; 407 | if (!feed) { 408 | api.memory.set("tempSavedAllGame", currentGameIndex); 409 | launchGame(current); 410 | } else { 411 | launchGame(feedCurrent); 412 | } 413 | } 414 | 415 | // Favorite Game / Skip Game Video 416 | if (api.keys.isFilters(event)) { 417 | event.accepted = true; 418 | if (!feed) { 419 | if (!settings["nosfx"]) 420 | sFav.play(); 421 | current.favorite = !current.favorite; 422 | } else { 423 | feedNext(); 424 | } 425 | } 426 | 427 | // Quick Search with X 428 | if (api.keys.isDetails(event)) { 429 | event.accepted = true; 430 | if (!feed) { 431 | keys.invoke() 432 | } 433 | } 434 | } 435 | 436 | Component.onCompleted: { 437 | positionViewAtIndex(currentIndex, GridView.Center); 438 | } 439 | } 440 | 441 | 442 | // Feed Stuff 443 | SortFilterProxyModel { 444 | id: gamesWithVideos; 445 | 446 | sourceModel: api.allGames; 447 | filters: [ 448 | ExpressionFilter { expression: { assets.video !== ''; } } 449 | ] 450 | } 451 | 452 | Video { 453 | id: feedPlayer; 454 | 455 | width: parent.width * 0.75 456 | height: parent.height * 0.75 457 | autoPlay: true 458 | 459 | anchors.horizontalCenter: parent.horizontalCenter 460 | anchors.bottom: parent.bottom 461 | anchors.bottomMargin: parent.height * 0.1 462 | 463 | visible: feed 464 | 465 | fillMode: VideoOutput.PreserveAspectFit 466 | 467 | onStatusChanged: { 468 | if (status === MediaPlayer.InvalidMedia) { 469 | console.log("VIDEO INVALID"); 470 | feedNext(); 471 | } 472 | if (status === MediaPlayer.EndOfMedia) { 473 | console.log("VIDEO EOF"); 474 | feedNext(); 475 | } 476 | } 477 | 478 | MouseArea { 479 | anchors.fill: parent 480 | 481 | onClicked: { 482 | launchGame(feedCurrent) 483 | } 484 | } 485 | } 486 | 487 | Rectangle { 488 | id: feedPlayerBG 489 | anchors.centerIn: feedPlayer; 490 | 491 | width: feedPlayer.width 492 | height: feedPlayer.height 493 | 494 | visible: feedPlayer.visible 495 | 496 | z: feedPlayer.z - 1 497 | 498 | color: colors["plainBG"] 499 | } 500 | 501 | Text { 502 | id: feedInfoLabel 503 | width: parent.width * .9 504 | 505 | y: parent.height * 0.91 506 | 507 | text: loc.all_feed_instructions 508 | color: colors["text"] 509 | 510 | visible: feed 511 | 512 | // Alignment 513 | horizontalAlignment: Text.AlignHCenter 514 | 515 | font.family: gilroyLight.name 516 | font.pixelSize: parent.height * .025 517 | 518 | anchors.left: parent.left 519 | anchors.leftMargin: parent.width * 0.05 520 | } 521 | 522 | DropShadow { 523 | anchors.fill: feedPlayerBG; 524 | source: feedPlayerBG; 525 | 526 | visible: feedPlayerBG.visible 527 | 528 | opacity: giShadowOp 529 | 530 | radius: giShadowRad * 2 531 | samples: radius * 2 + 1 532 | z: feedPlayerBG.z - 1 533 | } 534 | 535 | Timer { 536 | id: feedRepeatTimer 537 | 538 | interval: 500 539 | repeat: false 540 | running: false 541 | } 542 | 543 | Keys.onPressed: { 544 | if (event.isAutoRepeat) { 545 | return 546 | } 547 | 548 | // Feed Mode 549 | if (api.keys.isPageUp(event)) { 550 | event.accepted = true; 551 | 552 | if (feedRepeatTimer.running == false) { 553 | feed = !feed; 554 | theme.isFeed = !theme.isFeed 555 | 556 | if (feed) { 557 | feedNext(); 558 | } else { 559 | feedPlayer.stop(); 560 | } 561 | 562 | feedRepeatTimer.start() 563 | } 564 | 565 | } 566 | } 567 | 568 | function feedNext() { 569 | const gindex = Math.floor(Math.random() * gamesWithVideos.count); 570 | feedCurrent = api.allGames.get(gamesWithVideos.mapToSource(gindex)); 571 | 572 | console.log(feedCurrent.title); 573 | feedPlayer.source = feedCurrent.assets.video; 574 | 575 | console.log(feedPlayer.source); 576 | feedPlayer.play(); 577 | } 578 | 579 | Component.onCompleted: { 580 | if (api.memory.has("tempSavedAllGame")) { 581 | if (!settings["forceHome"]) { 582 | allView.currentIndex = Math.min(api.memory.get("tempSavedAllGame"), searchSort.count === 0 ? api.allGames.count : searchSort.count); 583 | } 584 | api.memory.unset("tempSavedAllGame"); 585 | } 586 | feedPlayer.stop(); 587 | } 588 | 589 | Connections { 590 | target: theme 591 | 592 | function onVideoControl(pause) { 593 | if (pause) { 594 | feedPlayer.pause() 595 | } else if (feed) { 596 | feedPlayer.play() 597 | } 598 | } 599 | } 600 | 601 | } 602 | -------------------------------------------------------------------------------- /Theme/Collections.qml: -------------------------------------------------------------------------------- 1 | import QtQuick 2.8 2 | import QtMultimedia 5.9 3 | import QtQuick.Layouts 1.15 4 | import QtGraphicalEffects 1.15 5 | import QtQuick.Window 2.15 6 | 7 | import SortFilterProxyModel 0.2 8 | 9 | import "../GameItems" 10 | 11 | FocusScope { 12 | id: collects 13 | 14 | /* gameView shows the games in a collection once clicked. 15 | * It sets the visible property of each GridView here. 16 | * false: Collections View 17 | * true: Game View 18 | */ 19 | property bool gameView: false 20 | 21 | /* Sets whether or not you're in a collection 22 | * 0: Collections 23 | * 1: Games 24 | */ 25 | property var collection: 0 26 | 27 | // Adds a delay to mouse clicks on the collection screen so that they don't immediately click a game 28 | property bool interact: true 29 | 30 | // Collections Title 31 | Text { 32 | id: tlText 33 | width: parent.width * .9 34 | 35 | y: parent.height * 0.075 36 | 37 | text: loc.collections_title 38 | color: colors["text"] 39 | 40 | font.family: gilroyLight.name 41 | font.pixelSize: parent.height * .05 42 | 43 | // Alignment 44 | horizontalAlignment: settings["centerTitles"] ? Text.AlignHCenter : Text.AlignLeft 45 | 46 | anchors.left: parent.left 47 | anchors.leftMargin: parent.width * 0.05 48 | 49 | opacity: gameView ? 0 : 1 50 | } 51 | 52 | // Games Title 53 | Text { 54 | id: llText 55 | width: parent.width * .9 56 | 57 | y: parent.height * 0.075 58 | 59 | text: collection.name 60 | color: colors["text"] 61 | 62 | font.family: gilroyLight.name 63 | font.pixelSize: parent.height * .05 64 | 65 | // Alignment 66 | horizontalAlignment: settings["centerTitles"] ? Text.AlignHCenter : Text.AlignLeft 67 | 68 | anchors.left: parent.left 69 | anchors.leftMargin: parent.width * 0.05 70 | 71 | opacity: gameView ? 1 : 0 72 | } 73 | 74 | // Clickable Mouse Navigation 75 | Item { 76 | height: parent.height * 0.075 77 | width: height 78 | y: parent.height * 0.075 79 | anchors.right: parent.right 80 | anchors.rightMargin: parent.width * 0.05 81 | visible: gameView && settings["mouseNav"] 82 | Behavior on y { 83 | SmoothedAnimation { velocity: animVel } 84 | } 85 | Text { 86 | text: icons.touch_up 87 | anchors.centerIn: parent 88 | font { 89 | family: icons.name; 90 | pixelSize: parent.height * .6 91 | } 92 | color: colors["text"] 93 | } 94 | 95 | MouseArea { 96 | anchors.fill: parent 97 | onClicked: { 98 | if (!settings["nosfx"]) 99 | sBack.play(); 100 | gameView = false; 101 | } 102 | } 103 | } 104 | 105 | /* collectionsView: Shows collections 106 | * Works just like a gameView, but has some key differences 107 | * 108 | */ 109 | GridView { 110 | id: collectionsView 111 | width: height * (2) 112 | height: parent.height * 0.75 //* (Math.ceil(api.allGames.count / 6)) 113 | 114 | anchors.top: parent.top 115 | anchors.topMargin: parent.height * .15 116 | anchors.horizontalCenter: parent.horizontalCenter 117 | 118 | cellWidth: (cellHeight * (2/3)) 119 | cellHeight: height / settings["collectionRows"] 120 | 121 | // Collections model from Pegasus 122 | model: api.collections 123 | 124 | delegate: Item { 125 | readonly property bool isCurrentItem: GridView.isCurrentItem 126 | // doubleFocus again focuses the highlighted item 127 | readonly property bool doubleFocus: collectionsView.focus && isCurrentItem 128 | 129 | width: GridView.view.cellWidth 130 | height: GridView.view.cellHeight 131 | 132 | Item { 133 | anchors { 134 | fill: parent 135 | margins: (doubleFocus) ? 0 : vpx(10) 136 | } 137 | 138 | Behavior on anchors.margins { 139 | SmoothedAnimation { velocity: marginAnimVel } 140 | } 141 | 142 | /* Instead of GINormal, this view uses GICusart 143 | * This is to permit collection art to show rather than game art. 144 | */ 145 | GICusart{ } 146 | 147 | /* 148 | Loader { 149 | anchors.fill: parent 150 | asynchronous: true 151 | sourceComponent: GICusart{} 152 | active: collects.focus 153 | visible: status === Loader.Ready 154 | } 155 | */ 156 | 157 | // Click functionality 158 | MouseArea { 159 | anchors.fill: parent 160 | 161 | onClicked: { 162 | if (isCurrentItem) { 163 | if (!settings["nosfx"]) sAccept.play(); 164 | collection = api.collections.get(collectionsView.currentIndex); 165 | 166 | // We set interact to false so that the click doesn't interact 167 | interact = false; 168 | gameView = true; 169 | 170 | // Timeout is .5s, enough to let go of the previous click 171 | setTimeout({interact = true}, 500) 172 | } else { 173 | if (!settings["nosfx"]) sNav.play(); 174 | collectionsView.currentIndex = index; 175 | } 176 | } 177 | } 178 | } 179 | } 180 | 181 | clip: true 182 | focus: (menu == 2) && !(gameView) 183 | visible: !gameView 184 | 185 | // Go up 186 | Keys.onUpPressed: { 187 | if (!settings["nosfx"]) sNav.play(); 188 | moveCurrentIndexUp(); 189 | } 190 | 191 | // Go down with special property 192 | Keys.onDownPressed: { 193 | if (!settings["nosfx"]) sNav.play(); 194 | 195 | // Go to last element if no element below on non-final row 196 | if (collectionsView.currentIndex + (settings["collectionRows"] * 3) >= collectionsView.count && collectionsView.currentIndex % (settings["collectionRows"] * 3) > (collectionsView.count - 1) % (settings["collectionRows"] * 3)) 197 | collectionsView.currentIndex = collectionsView.count - 1; 198 | else { 199 | moveCurrentIndexDown(); 200 | } 201 | } 202 | // Go left/right 203 | Keys.onLeftPressed: { if (!settings["nosfx"]) sNav.play(); moveCurrentIndexLeft() } 204 | Keys.onRightPressed: { if (!settings["nosfx"]) sNav.play(); moveCurrentIndexRight() } 205 | 206 | Keys.onPressed: { 207 | // Stop auto repeat: Don't open a game if A is held down. 208 | if (event.isAutoRepeat) { 209 | return 210 | } 211 | 212 | // Open the current collection 213 | if (api.keys.isAccept(event)) { 214 | if (!settings["nosfx"]) 215 | sAccept.play(); 216 | // Set the current Collection 217 | collection = api.collections.get(collectionsView.currentIndex) 218 | gameView = true 219 | } 220 | } 221 | 222 | Component.onCompleted: { 223 | positionViewAtIndex(currentIndex, GridView.Center); 224 | } 225 | } 226 | 227 | // Actual Games in a collection 228 | GridView { 229 | id: collectionGamesView 230 | width: settings["wide"] ? height * (2.14) : height * (2) 231 | height: settings["wide"] ? parent.height * 0.7 : parent.height * 0.75 //* (Math.ceil(api.allGames.count / 6)) 232 | 233 | anchors.top: parent.top 234 | anchors.topMargin: parent.height * .15 235 | anchors.horizontalCenter: parent.horizontalCenter 236 | 237 | cellWidth: getCellWidth(cellHeight, true)//settings["wide"] ? (cellHeight * (92/43)) : (cellHeight * (2/3)) 238 | cellHeight: height / settings["gamesRows"] 239 | 240 | // Games in the current collection is the model 241 | model: collection.games 242 | 243 | delegate: Item { 244 | readonly property bool isCurrentItem: GridView.isCurrentItem 245 | // Again, doubleFocus, doing the same thing 246 | readonly property bool doubleFocus: collectionGamesView.focus && isCurrentItem 247 | 248 | width: GridView.view.cellWidth 249 | height: GridView.view.cellHeight 250 | 251 | Item { 252 | anchors { 253 | fill: parent 254 | margins: (doubleFocus) ? 0 : vpx(10) 255 | } 256 | 257 | Behavior on anchors.margins { 258 | SmoothedAnimation { velocity: marginAnimVel } 259 | } 260 | 261 | GINormal { } 262 | 263 | /* 264 | Loader { 265 | anchors.fill: parent 266 | asynchronous: true 267 | sourceComponent: GINormal{} 268 | active: collects.focus 269 | visible: status === Loader.Ready 270 | } 271 | */ 272 | 273 | // Click functionality 274 | MouseArea { 275 | anchors.fill: parent 276 | onClicked: { 277 | if (isCurrentItem) { 278 | api.memory.set("tempSavedCollection", collectionsView.currentIndex); 279 | api.memory.set("tempSavedCollectionGame", index); 280 | launchGame(modelData); 281 | } 282 | else { 283 | collectionGamesView.currentIndex = index; 284 | if (!settings["nosfx"]) 285 | sNav.play(); 286 | } 287 | } 288 | } 289 | } 290 | } 291 | 292 | clip: true 293 | focus: (menu == 2) && (gameView) 294 | visible: gameView 295 | 296 | // Move up, down, left & right like collectionsView 297 | Keys.onUpPressed: { 298 | if (!settings["nosfx"]) sNav.play(); 299 | moveCurrentIndexUp(); 300 | } 301 | Keys.onDownPressed: { 302 | if (!settings["nosfx"]) sNav.play(); 303 | 304 | // Go to last element if no element below on non-final row 305 | if (settings["wide"]) { 306 | if (collectionGamesView.currentIndex + (settings["gamesRows"]) >= collectionGamesView.count && collectionGamesView.currentIndex % (settings["gamesRows"]) > (collectionGamesView.count - 1) % (settings["gamesRows"])) 307 | collectionGamesView.currentIndex = collectionGamesView.count - 1; 308 | else { 309 | moveCurrentIndexDown(); 310 | } 311 | } else { 312 | if (collectionGamesView.currentIndex + (settings["gamesRows"] * 3) >= collectionGamesView.count && collectionGamesView.currentIndex % (settings["gamesRows"] * 3) > (collectionGamesView.count - 1) % (settings["gamesRows"] * 3)) 313 | collectionGamesView.currentIndex = collectionGamesView.count - 1; 314 | else { 315 | moveCurrentIndexDown(); 316 | } 317 | } 318 | } 319 | Keys.onLeftPressed: { if (!settings["nosfx"]) sNav.play(); moveCurrentIndexLeft() } 320 | Keys.onRightPressed: { if (!settings["nosfx"]) sNav.play(); moveCurrentIndexRight() } 321 | 322 | Keys.onPressed: { 323 | if (event.isAutoRepeat) { 324 | return 325 | } 326 | 327 | // Launch game, only on interact 328 | if (api.keys.isAccept(event)) { 329 | if (interact) { 330 | event.accepted = true; 331 | api.memory.set("tempSavedCollection", collectionsView.currentIndex); 332 | api.memory.set("tempSavedCollectionGame", collectionGamesView.currentIndex); 333 | launchGame(collection.games.get(collectionGamesView.currentIndex)) 334 | } 335 | } 336 | 337 | // Go back to the collections 338 | if (api.keys.isCancel(event)) { 339 | if (!settings["nosfx"]) 340 | sBack.play(); 341 | event.accepted = true; 342 | gameView = false 343 | } 344 | 345 | // Favorite a game 346 | if (api.keys.isFilters(event)) { 347 | if (!settings["nosfx"]) 348 | sFav.play(); 349 | event.accepted = true; 350 | collection.games.get(collectionGamesView.currentIndex).favorite = !collection.games.get(collectionGamesView.currentIndex).favorite; 351 | } 352 | } 353 | 354 | Component.onCompleted: { 355 | positionViewAtIndex(currentIndex, GridView.Center); 356 | } 357 | } 358 | 359 | Component.onCompleted: { 360 | if (api.memory.has("tempSavedCollection")) { 361 | if (!settings["forceHome"]) { 362 | if (api.memory.get("tempSavedCollection") >= 0 && 363 | api.memory.get("tempSavedCollection") < api.collections.count) { 364 | collectionsView.currentIndex = api.memory.get("tempSavedCollection"); 365 | 366 | collection = api.collections.get(collectionsView.currentIndex); 367 | gameView = true; 368 | 369 | collectionGamesView.currentIndex = api.memory.get("tempSavedCollectionGame"); 370 | } 371 | } 372 | 373 | api.memory.unset("tempSavedCollection") 374 | api.memory.unset("tempSavedCollectionGame") 375 | } 376 | } 377 | 378 | } 379 | -------------------------------------------------------------------------------- /Theme/Home.qml: -------------------------------------------------------------------------------- 1 | import QtQuick 2.8 2 | import QtMultimedia 5.9 3 | import QtQuick.Layouts 1.15 4 | import QtGraphicalEffects 1.15 5 | import QtQuick.Window 2.15 6 | 7 | import SortFilterProxyModel 0.2 8 | 9 | import "../GameItems" 10 | 11 | FocusScope { 12 | id: home 13 | 14 | /* Focused changes the view for the home screen. 15 | * It scrolls the page to the favorites when they are focused. 16 | * 0: recent 17 | * 1: favorites 18 | */ 19 | property int focused: 0 20 | 21 | // Add more recent games with moreRecents 22 | property int maxRecents: settings["moreRecent"] ? 20 : 10 23 | 24 | // Sort Recents 25 | 26 | // Sorts by recent games, includes all games 27 | SortFilterProxyModel { 28 | id: sort_last_played_base 29 | sourceModel: api.allGames 30 | sorters: RoleSorter { roleName: "lastPlayed"; sortOrder: Qt.DescendingOrder; } 31 | } 32 | 33 | // Sorts the recent games model up to maxRecents 34 | SortFilterProxyModel { 35 | id: recent 36 | sourceModel: sort_last_played_base 37 | filters: IndexFilter { minimumIndex: 0; maximumIndex: maxRecents; } 38 | } 39 | 40 | // Sort Favorites 41 | 42 | // Filters by all favorite games, sorting by ascending order. 43 | SortFilterProxyModel { 44 | id: favorites 45 | sourceModel: api.allGames 46 | sorters: RoleSorter { roleName: "sortBy"; sortOrder: Qt.AscendingOrder; } 47 | filters: ValueFilter { roleName: "favorite"; value: true; } 48 | } 49 | 50 | // Define Current Game 51 | /* 52 | property var currentGame: { 53 | if (focused == 0) // If on recent, set to the current recent view game. 54 | api.allGames.get(sort_last_played_base.mapToSource(recentView.currentIndex)) 55 | if (focused == 1) // If on favorites, set to the current favorited game 56 | api.allGames.get(favorites.mapToSource(favoriteView.currentIndex)) 57 | else 58 | return null 59 | } 60 | */ 61 | 62 | // This is the y position of the whole UI. It moves the recent view out of the way when the favorites are focused. 63 | property var uiY: { 64 | if (focused == 1) 65 | parent.height * -0.4 66 | else 67 | parent.height * 0.15 68 | } 69 | 70 | // Animation velocity for the vertical movement 71 | property int animVel: 1200 72 | 73 | // 74 | // Layouts 75 | // 76 | 77 | // Recent Games Text 78 | Text { 79 | id: recentTitle 80 | width: parent.width * .9 81 | 82 | y: uiY - parent.height * 0.075 83 | 84 | text: loc.home_recent 85 | color: colors["text"] 86 | 87 | font.family: gilroyLight.name 88 | font.pixelSize: parent.height * .05 89 | 90 | // Alignment 91 | horizontalAlignment: settings["centerTitles"] ? Text.AlignHCenter : Text.AlignLeft 92 | 93 | anchors.left: parent.left 94 | anchors.leftMargin: parent.width * 0.05 95 | 96 | Behavior on y { 97 | SmoothedAnimation { velocity: animVel } 98 | } 99 | } 100 | 101 | // Favorite Games Text 102 | Text { 103 | id: favTitle 104 | width: parent.width * .9 105 | 106 | y: uiY + parent.height * 0.475 107 | 108 | text: loc.home_favorite 109 | color: colors["text"] 110 | 111 | font.family: gilroyLight.name 112 | font.pixelSize: parent.height * .05 113 | 114 | // Alignment 115 | horizontalAlignment: settings["centerTitles"] ? Text.AlignHCenter : Text.AlignLeft 116 | 117 | anchors.left: parent.left 118 | anchors.leftMargin: parent.width * 0.05 119 | 120 | Behavior on y { 121 | SmoothedAnimation { velocity: animVel } 122 | } 123 | } 124 | 125 | // Clickable icon to scroll back up 126 | Item { 127 | width: height 128 | height: parent.height * 0.1 129 | y: uiY + parent.height * 0.45 130 | anchors.right: parent.right 131 | anchors.rightMargin: parent.width * 0.05 132 | visible: settings["mouseNav"] 133 | 134 | Behavior on y { 135 | SmoothedAnimation { velocity: animVel } 136 | } 137 | 138 | Text { 139 | text: icons.touch_up 140 | anchors.centerIn: parent 141 | font { 142 | family: icons.name; 143 | pixelSize: parent.height * .6 144 | } 145 | color: colors["text"] 146 | } 147 | 148 | MouseArea { 149 | anchors.fill: parent 150 | onClicked: { 151 | if (focused == 1) { 152 | if (!settings["nosfx"]) 153 | sNav.play(); 154 | focused = 0; 155 | } 156 | } 157 | } 158 | } 159 | 160 | // Recent Games List 161 | // Shows all the games you've recently played. 162 | ListView { 163 | id: recentView 164 | width: parent.width * 0.9 165 | height: parent.height * 0.4 166 | 167 | y: uiY 168 | 169 | orientation: ListView.Horizontal 170 | model: recent 171 | 172 | displayMarginEnd: 20 173 | 174 | delegate: Item { 175 | readonly property bool isCurrentItem: ListView.isCurrentItem 176 | // doubleFocus property only selects game when the view and item is this one 177 | readonly property bool doubleFocus: recentView.focus && isCurrentItem 178 | 179 | // Set this game to be wide if wide mode is enabled, 180 | // OR if it is the first game and the override is disabled. 181 | width: settings["wide"] || (index == 0 && !settings["forceRecentNarrow"]) ? ListView.view.height * (settings["diffAspect"] ? 16/9 : 92/43) : ListView.view.height * (settings["diffAspect"] ? 3/4 : 2/3) 182 | height: ListView.view.height 183 | 184 | Item { 185 | id: gameItemRoot 186 | 187 | anchors { 188 | fill: parent 189 | margins: (doubleFocus) ? 0 : vpx(10) 190 | } 191 | 192 | Behavior on anchors.margins { 193 | SmoothedAnimation { velocity: marginAnimVel } 194 | } 195 | 196 | // wideHead is set based on forceRecentNarrow, changing art and visual 197 | // properties of the game 198 | GINormal { wideHead: !settings["forceRecentNarrow"] } 199 | 200 | /* 201 | Loader { 202 | anchors.fill: parent 203 | asynchronous: true 204 | sourceComponent: GINormal { wideHead: true } 205 | active: (home.focus) 206 | visible: status === Loader.Ready 207 | } 208 | */ 209 | 210 | // Click Functionality 211 | MouseArea { 212 | anchors.fill: parent 213 | onClicked: { 214 | if (doubleFocus) 215 | launchGame(modelData); 216 | else 217 | if (focused == 1) 218 | focused = 0; 219 | if (!settings["nosfx"]) 220 | sNav.play(); 221 | recentView.currentIndex = index; 222 | } 223 | } 224 | } 225 | } 226 | 227 | // Instant scrolling 228 | highlightMoveDuration: 0 229 | highlightResizeDuration: 0 230 | 231 | anchors.right: parent.right 232 | anchors.rightMargin: parent.width * 0.05 233 | 234 | clip: false 235 | focus: (focused == 0) && (menu == 0) 236 | 237 | Behavior on y { 238 | SmoothedAnimation { velocity: animVel } 239 | } 240 | 241 | // Scroll down when down is pressed 242 | Keys.onDownPressed: { 243 | if (!settings["nosfx"]) sNav.play(); 244 | focused = 1; 245 | } 246 | 247 | // Move left/right 248 | Keys.onLeftPressed: { 249 | if (!settings["nosfx"]) sNav.play(); 250 | decrementCurrentIndex(); 251 | } 252 | Keys.onRightPressed: { 253 | if (!settings["nosfx"]) sNav.play(); 254 | incrementCurrentIndex(); 255 | } 256 | 257 | // Game Actions 258 | Keys.onPressed: { 259 | if (event.isAutoRepeat) { 260 | return 261 | } 262 | 263 | // Launch the current Game 264 | if (api.keys.isAccept(event)) { 265 | event.accepted = true; 266 | launchGame(api.allGames.get(sort_last_played_base.mapToSource(recentView.currentIndex))) 267 | } 268 | 269 | // Favorite/Unfavorite the current game 270 | if (api.keys.isFilters(event)) { 271 | event.accepted = true; 272 | if (!settings["nosfx"]) 273 | sFav.play(); 274 | 275 | api.allGames.get(sort_last_played_base.mapToSource(recentView.currentIndex)).favorite = !api.allGames.get(sort_last_played_base.mapToSource(recentView.currentIndex)).favorite; 276 | } 277 | } 278 | } 279 | 280 | // Favorite Games List 281 | // Shows all the games you've favorited. 282 | GridView { 283 | id: favoriteView 284 | width: settings["wide"] ? height * (2.14) : height * (2) 285 | height: settings["wide"] ? parent.height * 0.7 : parent.height * 0.75 //* (Math.ceil(favorites.count / 6)) 286 | 287 | y: uiY + parent.height * 0.575 288 | anchors.horizontalCenter: parent.horizontalCenter 289 | 290 | cellWidth: getCellWidth(cellHeight, true) //settings["wide"] ? (cellHeight * (92/43)) : (cellHeight * (2/3)) 291 | cellHeight: height / settings["gamesRows"] /// (Math.ceil(favorites.count / 6)) 292 | 293 | //currentIndex: 0 294 | model: favorites 295 | 296 | delegate: Item { 297 | readonly property bool isCurrentItem: GridView.isCurrentItem 298 | // doubleFocus property only selects game when the view and item is this one 299 | readonly property bool doubleFocus: favoriteView.focus && isCurrentItem 300 | 301 | width: GridView.view.cellWidth 302 | height: GridView.view.cellHeight 303 | 304 | Item { 305 | anchors { 306 | fill: parent 307 | margins: (doubleFocus) ? 0 : vpx(10) 308 | } 309 | 310 | Behavior on anchors.margins { 311 | SmoothedAnimation { velocity: marginAnimVel } 312 | } 313 | 314 | GINormal { } 315 | 316 | // Click behavior 317 | MouseArea { 318 | anchors.fill: parent 319 | onClicked: { 320 | if (doubleFocus) 321 | launchGame(modelData); 322 | else 323 | if (focused == 0) 324 | focused = 1; 325 | if (!settings["nosfx"]) 326 | sNav.play(); 327 | favoriteView.currentIndex = index; 328 | } 329 | } 330 | } 331 | } 332 | 333 | clip: true 334 | focus: (focused == 1) && (menu == 0) 335 | 336 | Behavior on y { 337 | SmoothedAnimation { velocity: animVel } 338 | } 339 | 340 | // Scroll back up if at the top, otherwise just move up 341 | Keys.onUpPressed: { 342 | if (!settings["nosfx"]) 343 | sNav.play(); 344 | 345 | /* 346 | 347 | TOP ROW: 348 | normal: 349 | n * 3 rows 350 | wide: 351 | n rows 352 | 353 | */ 354 | 355 | if (settings["wide"]) { 356 | if (favoriteView.currentIndex < settings["gamesRows"]) 357 | focused = 0 358 | } else { 359 | if (favoriteView.currentIndex < (settings["gamesRows"] * 3)) 360 | focused = 0 361 | } 362 | if (focused == 1) 363 | moveCurrentIndexUp(); 364 | } 365 | 366 | // Scroll down 367 | Keys.onDownPressed: { 368 | if (!settings["nosfx"]) sNav.play(); 369 | 370 | // Go to last element if no element below on non-final row 371 | if (settings["wide"]) { 372 | if (favoriteView.currentIndex + (settings["gamesRows"]) >= favoriteView.count && favoriteView.currentIndex % (settings["gamesRows"]) > (favoriteView.count - 1) % (settings["gamesRows"])) 373 | favoriteView.currentIndex = favoriteView.count - 1; 374 | else { 375 | moveCurrentIndexDown(); 376 | } 377 | } else { 378 | if (favoriteView.currentIndex + (settings["gamesRows"] * 3) >= favoriteView.count && favoriteView.currentIndex % (settings["gamesRows"] * 3) > (favoriteView.count - 1) % (settings["gamesRows"] * 3)) 379 | favoriteView.currentIndex = favoriteView.count - 1; 380 | else { 381 | moveCurrentIndexDown(); 382 | } 383 | } 384 | } 385 | 386 | // Move left/right 387 | Keys.onLeftPressed: { 388 | if (!settings["nosfx"]) sNav.play(); 389 | moveCurrentIndexLeft(); 390 | } 391 | Keys.onRightPressed: { 392 | if (!settings["nosfx"]) sNav.play(); 393 | moveCurrentIndexRight(); 394 | } 395 | 396 | // Game Actions 397 | Keys.onPressed: { 398 | if (event.isAutoRepeat) { 399 | return 400 | } 401 | 402 | // Launch selected game 403 | if (api.keys.isAccept(event)) { 404 | event.accepted = true; 405 | launchGame(api.allGames.get(favorites.mapToSource(favoriteView.currentIndex))) 406 | } 407 | } 408 | } 409 | } 410 | -------------------------------------------------------------------------------- /Theme/PegaKey/KeyButton.qml: -------------------------------------------------------------------------------- 1 | import QtQuick 2.0 2 | import QtMultimedia 5.9 3 | 4 | Rectangle { 5 | /* KeyButton 6 | * Defines the default style for keyboard buttons as a RoundButton 7 | * 8 | */ 9 | 10 | signal clicked 11 | 12 | id: btn 13 | radius: 16 14 | 15 | property var clickedColor: "#000000" 16 | property var regColor: "#FFFFFF" 17 | property var textColor: "#888888" 18 | 19 | color: clickArea.containsPress ? clickedColor : regColor 20 | 21 | property string label: "" 22 | property bool large: false 23 | 24 | Text { 25 | anchors.centerIn: parent 26 | 27 | text: label 28 | color: textColor 29 | 30 | font.family: gilroyLight.name 31 | font.pixelSize: large ? btn.height / 2 : btn.height / 5 32 | } 33 | 34 | MouseArea { 35 | id: clickArea 36 | anchors.fill: parent 37 | 38 | onPressed: { 39 | btn.clicked() 40 | } 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /Theme/PegaKey/Keyboard.qml: -------------------------------------------------------------------------------- 1 | import QtQuick 2.0 2 | import QtMultimedia 5.9 3 | 4 | Item { 5 | 6 | /* Keyboard 7 | * Keyboard.qml instantiates a KeyboardObject. It is not the keyboard itself. 8 | * It obviously shows and hides the keyboard, but it also converts several keys. 9 | * 10 | */ 11 | 12 | id: kcreator 13 | 14 | focus: false 15 | 16 | // Signals 17 | signal invoked() 18 | signal sendKey(string text) 19 | signal done() 20 | 21 | // Default Keyboard Colors 22 | property var kcolors: { 23 | "bg": "#FFFFFF", // KEYBOARD: Background 24 | "key": "#DDDDDD", // KEYBOARD: Key Background 25 | "keyPush": "#BBBBBB", // KEYBOARD: Key Background when clicked 26 | "keyHighlight": "#121212", // KEYBOARD: Selected Key Highlight 27 | "text": "#121212" // KEYBOARD: Text 28 | } 29 | 30 | // Quick Character Setting 31 | property string back: "\u2190" 32 | property string enter: "\u2192" 33 | property string shiftc: "\u2191" 34 | 35 | property url sfxSource: "" 36 | property bool quietSfx: false 37 | property bool muteSfx: false 38 | 39 | // Typing Sound Effect 40 | SoundEffect { 41 | id: kSfx 42 | source: sfxSource 43 | volume: quietSfx ? 0.5 : 1.0 44 | } 45 | 46 | // Invokes the keyboard (shows it) 47 | function invoke() { 48 | keyboard.visible = true; 49 | keyboard.focus = true; 50 | // This allows the keyboard to immediately accept presses vs waiting to move the cursor 51 | keyboard.focusEnableKB(); 52 | } 53 | 54 | function invokeNoFocus() { 55 | keyboard.visible = true; 56 | } 57 | 58 | function hide() { 59 | kcreator.done(); 60 | keyboard.focus = false; 61 | keyboard.visible = false; 62 | } 63 | 64 | // The actual Keyboard Object Keyboard.qml shows 65 | KeyboardObject { 66 | id: keyboard 67 | visible: false 68 | colors: kcolors 69 | 70 | backChar: back 71 | enterChar: enter 72 | shiftChar: shiftc 73 | 74 | width: theme.width 75 | height: theme.height * 0.6 76 | 77 | anchors.bottom: parent.bottom 78 | 79 | // Send Key is a signal of KeyboardObject.qml as well. 80 | onSendKey: { 81 | if (!muteSfx) { 82 | kSfx.play(); 83 | } 84 | 85 | if (text == back) { // Backspace Unicode Conversion 86 | kcreator.sendKey("bksp") 87 | } else if (text == enter) { // Enter Unicode Conversion 88 | keyboard.done() 89 | } else if (text == shiftc) { // Shift Unicode Conversion 90 | keyboard.shift = !keyboard.shift 91 | } else if (text == "&123" || text == "ABCD") { // Alt Conversion 92 | keyboard.alts = !keyboard.alts 93 | } else { 94 | kcreator.sendKey(text) 95 | if (keyboard.shift) { 96 | keyboard.shift = false 97 | } 98 | } 99 | } 100 | 101 | // Hides keyboard once done 102 | onDone: { 103 | hide(); 104 | } 105 | } 106 | 107 | } 108 | -------------------------------------------------------------------------------- /Theme/PegaKey/KeyboardObject.qml: -------------------------------------------------------------------------------- 1 | import QtQuick 2.0 2 | import QtMultimedia 5.9 3 | 4 | Item { 5 | id: kRoot 6 | 7 | /* KeyboardObject 8 | * The actual keyboard layout itself 9 | * 10 | */ 11 | 12 | // Signals 13 | signal sendKey(string text) 14 | signal done() 15 | 16 | 17 | 18 | // Character Properties 19 | property string backChar: "bksp" 20 | property string enterChar: "enter" 21 | property string shiftChar: "shft" 22 | 23 | 24 | // Some properties that modify the characters 25 | property bool shift: false 26 | property bool alts: false 27 | 28 | // Quick Rowspacing and columnspacing for easy access (gutter) 29 | property real rowspacing: width * 0.005 30 | property real colspacing: rowspacing //height * 0.01 31 | 32 | // Highlight color 33 | property var colors: {} 34 | 35 | // Current Row & Column 36 | property int curRow: 0 37 | property int curCol: 0 38 | 39 | // Block clicking below keyboard 40 | MouseArea {anchors.fill: parent} 41 | 42 | // Background: Parent rectangle has roundness 43 | Rectangle { 44 | anchors.fill: parent 45 | color: colors["bg"] 46 | 47 | radius: height / 16 48 | 49 | Rectangle { 50 | anchors.fill: parent 51 | color: parent.color 52 | 53 | anchors.topMargin: height / 2 54 | } 55 | } 56 | 57 | // Move up/down keyboard 58 | Keys.onUpPressed: { 59 | if (curRow <= 0) { 60 | curRow = 3 61 | } else { 62 | curRow -= 1 63 | } 64 | } 65 | Keys.onDownPressed: { 66 | if (curRow >= 3) { 67 | curRow = 0 68 | } else { 69 | curRow += 1 70 | } 71 | } 72 | 73 | // Move left on the keyboard. Note that wider keys are hardcoded here. 74 | Keys.onLeftPressed: { 75 | if (curRow == 0) { 76 | if (curCol <= 0) { 77 | curCol = 10 78 | } else { 79 | curCol -= 1 80 | } 81 | } else if (curRow == 1) { 82 | if (curCol <= 0) { 83 | curCol = 10 84 | } else { 85 | curCol -= 1 86 | } 87 | if (curCol >= 9) { 88 | curCol -= 1 89 | } 90 | } else if (curRow == 2) { 91 | if (curCol <= 1) { 92 | curCol = 10 93 | } else { 94 | curCol -= 1 95 | } 96 | if (curCol >= 9) { 97 | curCol -= 1 98 | } 99 | } else if (curRow == 3) { 100 | if (curCol <= 1) { 101 | curCol = 10 102 | } else if (curCol >= 3 && curCol <= 7) { 103 | curCol = 2 104 | } else { 105 | curCol -= 1 106 | } 107 | if (curCol >= 9) { 108 | curCol -= 1 109 | } 110 | } 111 | } 112 | 113 | // Move right on the keyboard. Note that wider keys are hardcoded here as well. 114 | Keys.onRightPressed: { 115 | if (curRow == 0) { 116 | if (curCol >= 10) { 117 | curCol = 0 118 | } else { 119 | curCol += 1 120 | } 121 | } else if (curRow == 1) { 122 | if (curCol >= 9) { 123 | curCol = 0 124 | } else { 125 | curCol += 1 126 | } 127 | } else if (curRow == 2) { 128 | if (curCol >= 9) { 129 | curCol = 0 130 | } else { 131 | curCol += 1 132 | } 133 | if (curCol <= 1) { 134 | curCol += 1 135 | } 136 | } else if (curRow == 3) { 137 | if (curCol >= 3 && curCol <= 7) { 138 | curCol = 8 139 | } else if (curCol >= 9) { 140 | curCol = 0 141 | } else { 142 | curCol += 1 143 | } 144 | if (curCol <= 1) { 145 | curCol += 1 146 | } 147 | } 148 | } 149 | 150 | // Other keys 151 | Keys.onPressed: { 152 | // Space Shortcut 153 | if (api.keys.isFilters(event)) { 154 | kRoot.sendKey(" ") 155 | } 156 | // Backspace Shortcut 157 | if (api.keys.isDetails(event)) { 158 | kRoot.sendKey(backChar) // Backspace 159 | } 160 | // Exit Shortcut 161 | if (api.keys.isCancel(event)) { 162 | event.accepted = true; 163 | kRoot.done() 164 | } 165 | } 166 | 167 | Item { 168 | id: keymap 169 | 170 | // The actual keys on the keyboard 171 | 172 | anchors.fill: parent 173 | anchors.leftMargin: parent.width * 0.05 174 | anchors.rightMargin: parent.width * 0.05 175 | 176 | anchors.topMargin: parent.height * 0.025 177 | anchors.bottomMargin: parent.height * 0.1 178 | 179 | Column { 180 | // Keyboard Column, with rows 181 | spacing: colspacing 182 | 183 | Row { // QWERTYUIOP 184 | spacing: rowspacing 185 | 186 | Repeater { 187 | /* Repeaters repeat the keys 188 | * Models have the following properties 189 | * key: Lowercase letter (default) 190 | * alt: Alternate character 191 | * w: Key Width 192 | * il: Lower index (used for selection) 193 | * ih: Higher index (used for selection) 194 | * 195 | */ 196 | model: [ 197 | {key: "q", alt: "1", w: 1, il: 0, ih: 0}, 198 | {key: "w", alt: "2", w: 1, il: 1, ih: 1}, 199 | {key: "e", alt: "3", w: 1, il: 2, ih: 2}, 200 | {key: "r", alt: "4", w: 1, il: 3, ih: 3}, 201 | {key: "t", alt: "5", w: 1, il: 4, ih: 4}, 202 | {key: "y", alt: "6", w: 1, il: 5, ih: 5}, 203 | {key: "u", alt: "7", w: 1, il: 6, ih: 6}, 204 | {key: "i", alt: "8", w: 1, il: 7, ih: 7}, 205 | {key: "o", alt: "9", w: 1, il: 8, ih: 8}, 206 | {key: "p", alt: "0", w: 1, il: 9, ih: 9}, 207 | {key: backChar, alt: backChar, w: 1, il: 10, ih: 10} 208 | ] 209 | 210 | delegate: KeyButton { 211 | label: alts ? (modelData.alt) : (shift ? modelData.key.toUpperCase() : modelData.key) 212 | 213 | width: modelData.w * keymap.width / 11 - rowspacing 214 | height: keymap.height / 4 - colspacing 215 | 216 | focus: curRow == 0 && (curCol >= modelData.il && curCol <= modelData.ih) 217 | 218 | clickedColor:colors["keyPush"] 219 | regColor: colors["key"] 220 | textColor: colors["text"] 221 | 222 | // Key Highlight 223 | Rectangle { 224 | anchors.fill: parent 225 | radius: parent.radius 226 | border.width: 2 227 | border.color: colors["keyHighlight"] 228 | color: "transparent" 229 | visible: curRow == 0 && (curCol >= modelData.il && curCol <= modelData.ih) 230 | } 231 | 232 | // Sending the key (click) 233 | onClicked: { 234 | kRoot.sendKey(label); 235 | curRow = 0; 236 | curCol = modelData.il; 237 | } 238 | 239 | // Sending the key (button) 240 | Keys.onPressed: { 241 | if (api.keys.isAccept(event)) { 242 | kRoot.sendKey(label) 243 | } 244 | } 245 | } 246 | 247 | /* The same thing with the keys here is done with the rest of the Rows. 248 | * 249 | */ 250 | } 251 | } 252 | 253 | Row { // ASDFGHJKL + Enter 254 | spacing: rowspacing 255 | 256 | Repeater { 257 | // Key model 258 | model: [ 259 | {key: "a", alt: "!", w: 1, il: 0, ih: 0}, 260 | {key: "s", alt: "@", w: 1, il: 1, ih: 1}, 261 | {key: "d", alt: "#", w: 1, il: 2, ih: 2}, 262 | {key: "f", alt: "$", w: 1, il: 3, ih: 3}, 263 | {key: "g", alt: "%", w: 1, il: 4, ih: 4}, 264 | {key: "h", alt: "&", w: 1, il: 5, ih: 5}, 265 | {key: "j", alt: "*", w: 1, il: 6, ih: 6}, 266 | {key: "k", alt: "(", w: 1, il: 7, ih: 7}, 267 | {key: "l", alt: ")", w: 1, il: 8, ih: 8}, 268 | {key: enterChar, alt: enterChar, w: 2, il: 9, ih: 10} 269 | ] 270 | 271 | // Button 272 | delegate: KeyButton { 273 | label: alts ? (modelData.alt) : (shift ? modelData.key.toUpperCase() : modelData.key) 274 | 275 | width: modelData.w * keymap.width / 11 - rowspacing 276 | height: keymap.height / 4 - colspacing 277 | 278 | focus: visible && curRow == 1 && (curCol >= modelData.il && curCol <= modelData.ih) 279 | 280 | clickedColor:colors["keyPush"] 281 | regColor: colors["key"] 282 | textColor: colors["text"] 283 | 284 | // Key send (click) 285 | onClicked: { 286 | kRoot.sendKey(label); 287 | curRow = 1; 288 | curCol = modelData.il; 289 | } 290 | // Key send (button) 291 | Keys.onPressed: { 292 | if (api.keys.isAccept(event)) { 293 | kRoot.sendKey(label) 294 | } 295 | } 296 | 297 | // Key Highlight 298 | Rectangle { 299 | anchors.fill: parent 300 | radius: parent.radius 301 | border.width: 2 302 | border.color: colors["keyHighlight"] 303 | color: "transparent" 304 | visible: curRow == 1 && (curCol >= modelData.il && curCol <= modelData.ih) 305 | } 306 | } 307 | } 308 | } 309 | 310 | Row { // sh + ZXCVBNM + sh 311 | spacing: rowspacing 312 | 313 | Repeater { 314 | model: [ 315 | {key: shiftChar, alt: shiftChar, w: 2, il: 0, ih: 1}, 316 | {key: "z", alt: "-", w: 1, il: 2, ih: 2}, 317 | {key: "x", alt: "'", w: 1, il: 3, ih: 3}, 318 | {key: "c", alt: '"', w: 1, il: 4, ih: 4}, 319 | {key: "v", alt: "_", w: 1, il: 5, ih: 5}, 320 | {key: "b", alt: ",", w: 1, il: 6, ih: 6}, 321 | {key: "n", alt: "?", w: 1, il: 7, ih: 7}, 322 | {key: "m", alt: "+", w: 1, il: 8, ih: 8}, 323 | {key: shiftChar, alt: shiftChar, w: 2, il: 9, ih: 10} 324 | ] 325 | 326 | delegate: KeyButton { 327 | label: alts ? (modelData.alt) : (shift ? modelData.key.toUpperCase() : modelData.key) 328 | 329 | width: modelData.w * keymap.width / 11 - rowspacing 330 | height: keymap.height / 4 - colspacing 331 | 332 | focus: visible && curRow == 2 && (curCol >= modelData.il && curCol <= modelData.ih) 333 | 334 | clickedColor:colors["keyPush"] 335 | regColor: colors["key"] 336 | textColor: colors["text"] 337 | 338 | // Key send (click) 339 | onClicked: { 340 | kRoot.sendKey(label); 341 | curRow = 2; 342 | curCol = modelData.il; 343 | } 344 | // Key send (button) 345 | Keys.onPressed: { 346 | if (api.keys.isAccept(event)) { 347 | kRoot.sendKey(label) 348 | } 349 | } 350 | 351 | // Key Highlight 352 | Rectangle { 353 | anchors.fill: parent 354 | radius: parent.radius 355 | border.width: 2 356 | border.color: colors["keyHighlight"] 357 | color: "transparent" 358 | visible: curRow == 2 && (curCol >= modelData.il && curCol <= modelData.ih) 359 | } 360 | } 361 | } 362 | } 363 | 364 | Row { // sh + ZXCVBNM + sh 365 | spacing: rowspacing 366 | 367 | Repeater { 368 | model: [ 369 | {key: "&123", alt: "ABCD", w: 2, il: 0, ih: 1}, 370 | {key: ".", alt: ".", w: 1, il: 2, ih: 2}, 371 | {key: " ", alt: " ", w: 5, il: 3, ih: 7}, 372 | {key: "-", alt: "-", w: 1, il: 8, ih: 8}, 373 | {key: "CLEAR", alt: "CLEAR", w: 2, il: 9, ih: 10} 374 | ] 375 | 376 | delegate: KeyButton { 377 | label: alts ? (modelData.alt) : (shift ? modelData.key.toUpperCase() : modelData.key) 378 | 379 | width: modelData.w * keymap.width / 11 - rowspacing 380 | height: keymap.height / 4 - colspacing 381 | 382 | focus: visible && curRow == 3 && (curCol >= modelData.il && curCol <= modelData.ih) 383 | 384 | clickedColor:colors["keyPush"] 385 | regColor: colors["key"] 386 | textColor: colors["text"] 387 | 388 | // Key send (click) 389 | onClicked: { 390 | kRoot.sendKey(label); 391 | curRow = 3; 392 | curCol = modelData.il; 393 | } 394 | // Key send (button) 395 | Keys.onPressed: { 396 | if (api.keys.isAccept(event)) { 397 | kRoot.sendKey(label) 398 | } 399 | } 400 | 401 | // Key Highlight 402 | Rectangle { 403 | anchors.fill: parent 404 | radius: parent.radius 405 | border.width: 2 406 | border.color: colors["keyHighlight"] 407 | color: "transparent" 408 | visible: curRow == 3 && (curCol >= modelData.il && curCol <= modelData.ih) 409 | } 410 | } 411 | } 412 | } 413 | 414 | } 415 | } 416 | 417 | 418 | 419 | function focusEnableKB() { 420 | if (curRow >= 3) { 421 | curRow = 0 422 | } else { 423 | curRow += 1 424 | } 425 | if (curRow <= 0) { 426 | curRow = 3 427 | } else { 428 | curRow -= 1 429 | } 430 | } 431 | 432 | } 433 | -------------------------------------------------------------------------------- /assets/SAFELY_REMOVABLE/OLD_DOCUMENTATION.md: -------------------------------------------------------------------------------- 1 | # Warning 2 | 3 | This is old documentation that was the original intent for this theme's documentation. I have decided instead to make this into just comments. 4 | 5 | 6 | 7 | ## In Depth Editing Information 8 | 9 | This section will detail this theme fully, in order to allow you to have a greater understanding of this theme as well as QML. This will serve well for those who wish to perform heavy modifications of this theme or fork this theme. It is highly recommended that you take a look at the following sources at times while you look at this information: 10 | 11 | - [QtQuick QML Types](https://doc.qt.io/qt-5/qtquick-qmlmodule.html) (note that a quick search for the type followed by 'QML' will yield information for that type; not all types are here) 12 | - [Pegasus Frontend Theme API](https://pegasus-frontend.org/docs/themes/api/) 13 | 14 | ### theme.qml 15 | 16 | `theme.qml` can be divided into several parts. We first import all necessary QML modules, going from `QtQuick 2.8` to `SortFilterProxyModel 0.2`. Afterwards, we import other parts of the theme. To read more about these parts, see [Theme Folder Pages](#theme-folder-pages) and [Game Items](#game-items). 17 | 18 | The next few sections are described below. 19 |

20 | 21 | #### Variables 22 | 23 | The first portion under the `FocusScope` is where we define all variables. A list of each is below. 24 | 25 | - `focus`: Set the FocusScope to be focused, so that it receives input. 26 | - `sw`, `sh`: Define quick screen width and height references, used instead of parent.width and parent.height in top-level items 27 | - `menu`: Sets the current menu page. This is used to create the home, search, collections and settings pages. See [Pages](#pages). 28 | - `focused`, `gameView`: Defines page behaviors in the home and collections pages respectively, defined here to not be affected in their respective pages. 29 | - FontLoaders: These `FontLoaders` simply define fonts for use throughout the theme. 30 | 31 | - `iconSize`, `marginAnimVel`, `giShadowRad`, `giShadowOp`: These values set several miscellaneous properties for several different parts where these properties would otherwise need to be defined in several places. 32 | - `iconSize` defines the size of the icons in the bottom bar. 33 | - `marginAnimVel` defines the speed in which the expansion/contraction animation for highlighting games. 34 | - `giShadowRad` defines the size of game box shadows. 35 | - `giShadowOp` defines the opacity of the same game box shadows as above. 36 | 37 | - Settings: The last variables defined are settings which correspond to those in the settings page. 38 | - `light`: Light Mode 39 | - `plainBG`: Plain (Flat) Background 40 | - `noBtns`: Removes button indicators 41 | - `sbsl`: Shows clock bar (originally restricted search functionality) 42 | - `nosfx`: Mutes all sound effects 43 | - `wide`: Wide game view 44 | - `quiet`: Quiets sound effects (halves volume) 45 | - `moreRecent`: Increases the number of games under Recent Games 46 | - `mouseNav`: Enables mouse navigation arrows 47 | - `enlargeBar`: Enlarges the bottom bar 48 | - `limSearch`: Limits search results to those which start with the search rather than contain the search 49 |

50 | 51 | #### bottomBar 52 | 53 | After defining the variables, we go on to define the bottom bar. This is used to indicate which page we are currently on. This `bottomBar` Item contains a row of images, a background rectangle and a MouseArea. 54 | 55 | For each image in this row, we get its image from `[THEME_FOLDER]/assets/theme/[image].svg`, as well as allowing for clicks on the icons to switch to the respective page. You can easily modify the icon sizes with the `iconSize` setting from [Variables](#variables), as well as changing the source of the icons. 56 | 57 | `bottomBar` also contains a background rectangle, which simply overlays over the rest of the content. Its color is changeable here. 58 | 59 | The MouseArea here is to block clicks that occur on the bar, preventing one from accidentally clicking an item under the bar when not intended. 60 | 61 | Finally, outside of the `bottomBar` itself are 2 other items. One is the indicator rectangle for the bar, which shows the icon currently selected. It takes a small shortcut with its width, using the home icon to set its width. Its x position is defined by an equation, which simply does the following: 62 | 1. Moves the indicator to the screen's center 63 | 2. Move the indicator left to the home icon, by moving it left 2 icons and 1.5 spaces between the icons (the .5 comes from the fact that there are an even number of icons, so the .5 places it on the icon just left of the center) 64 | 3. Moves it right one space and one icon multiplied by the current menu value (this is why menu is an integer: it allows the indicator to properly move right) 65 | The y position of the indicator rectangle is simply placed respective to the screen height. Finally, a behavior is defined, which animates the indicator's movement. 66 | 67 | The other item outside of the `bottomBar` is the BottomBarIcons item, the first of several items defined outside of the theme.qml file. BottomBarIcons.qml is located under `[THEME_FOLDER]/Bottombar`, and defines the controller icons for the bottom bar. These are simply QML rectangles which are placed on 2 rows, each varying in several properties. 68 | 69 | One potential idea for a modification to `bottomBar` is to change its position, which could be done by anchoring it to another side, changing the height and width, and converting the Row `bbImages` to a Column.

70 | 71 | 72 | #### Pages 73 | 74 | After defining the bottomBar, we move on to pages, which are the objects from Colcon to ClockBar. These contain the main functionality of the theme, but in theme.qml, their definitions here only serve to put them on the theme itself. 75 | 76 | In-depth information on each page is under [Theme Folder Pages](#theme-folder-pages). 77 | 78 | `Colcon` defines a simple converter for Launchbox shortnames, as Launchbox has several shortnames which do not match up with those of the logos in `[THEME_FOLDER]/assets/logos/banner/`. This was **stolen** :(. 79 | 80 | Next we have the `Home`, `All`, `Collections`, and `Settings` pages. These are the main pages that show up. Each one fills the screen, and has a focus which corresponds to the `menu` variable, also setting the visibility. To change which page is visible, we modify `menu`; see [Other Functionalities](#other-functionalities) for more information. 81 | 82 | Finally, we have the `ClockBar`, which is made visible through the `sbsl` variable and placed above the other parts of the theme. 83 |

84 | 85 | #### Other Visuals 86 | 87 | The last visual portions of theme.qml define the background of the theme. First is the background image (`backgroundImage`), which is the actual image of the background, placed under all other parts of the theme. To add some visual effects, we add a ShaderEffectSource and GaussianBlur applied over the image to add a blur effect. If either background image isn't present or `plainBG` is true, we show the plain background, which is simply a rectangle that fills the screen, placed over `backgroundImage`. 88 | 89 | #### Other Functionalities 90 | 91 | The end of theme.qml defines some non-visual functions. It starts by defining several sound effects, located in `[THEME_FOLDER]/assets/audio/`, which are used in numerous places in the theme. 92 | 93 | After the sound effects, we define the menu changing behavior. With the input of the nextPage and previousPage buttons (LB/L1 and RB/R1), we change the current page of the theme. These functions also allow the navigation to wrap around. 94 | 95 | Finally, we define a `launchGame()` function, which launches games. This is where we reach the end of theme.qml. 96 |

97 | 98 | ### Theme Folder Pages 99 | 100 | The following section goes through the files in the `[THEME_FOLDER]/Theme` directory. There are 6 files in this folder, which will be covered in the next sections. 101 | 102 | #### Home.qml 103 | 104 | Home.qml defines the home page of the theme, which shows the recent games and favorite games sections. Home.qml starts by defining a few variables and other items. 105 | 106 | - `maxRecents` defines the maximum number of games in the recent games list. 107 | - `sort_last_played_base`, `recent` and `favorites` define models for the recent and favorite games lists. `sort_last_played_base` defines a model with the last played games, and `recent` restricts that model to `maxRecents` items. `favorites` defines a model listing all favorited games, which are defined by pegasus. 108 | - `currentGame` defines the currently highlighted game. The block of code here sets the game to be the currently selected game in the currently selected list (recent or favorites), allowing for launching the game to work properly. 109 | - `uiY`, similar to `currentGame`, is defined by code. The code here changes this value whether or not the recent games or the favorite games are selected, changing the vertical position of the UI to scroll the page to the favorite games. 110 | - `animVel` defines the animation speed of the animation that plays on scroll. 111 |
112 | 113 | After we define these variables, we create 3 simple objects, 2 of which just define text to indicate each section, and the other creates a clickable arrow which scrolls the page back up. While the Text objects are relatively simple, with the only thing of note being the y position, the up arrow is different, as it has a MouseArea which scrolls the view back up, allowing for mouse-based navigation. This is disabled if `mouseNav` is false. 114 | 115 | We then have a ListView, which shows our recent games. While there is lots of stuff here, the only thing of note is the `doubleFocus` property of the delegate Item, which highlights the item if the ListView and itself is focused. As well, the GINormal Item has the `wideHead` property set to true, making its first item wider. 116 | 117 | 118 | 119 | 120 | ### Game Items 121 | 122 | ### Other Parts 123 | 124 | -------------------------------------------------------------------------------- /assets/SAFELY_REMOVABLE/library-icons-font/README.txt: -------------------------------------------------------------------------------- 1 | This webfont is generated by https://fontello.com open source project. 2 | 3 | 4 | ================================================================================ 5 | Please, note, that you should obey original font licenses, used to make this 6 | webfont pack. Details available in LICENSE.txt file. 7 | 8 | - Usually, it's enough to publish content of LICENSE.txt file somewhere on your 9 | site in "About" section. 10 | 11 | - If your project is open-source, usually, it will be ok to make LICENSE.txt 12 | file publicly available in your repository. 13 | 14 | - Fonts, used in Fontello, don't require a clickable link on your site. 15 | But any kind of additional authors crediting is welcome. 16 | ================================================================================ 17 | 18 | 19 | Comments on archive content 20 | --------------------------- 21 | 22 | - /font/* - fonts in different formats 23 | 24 | - /css/* - different kinds of css, for all situations. Should be ok with 25 | twitter bootstrap. Also, you can skip style and assign icon classes 26 | directly to text elements, if you don't mind about IE7. 27 | 28 | - demo.html - demo file, to show your webfont content 29 | 30 | - LICENSE.txt - license info about source fonts, used to build your one. 31 | 32 | - config.json - keeps your settings. You can import it back into fontello 33 | anytime, to continue your work 34 | 35 | 36 | Why so many CSS files ? 37 | ----------------------- 38 | 39 | Because we like to fit all your needs :) 40 | 41 | - basic file, .css - is usually enough, it contains @font-face 42 | and character code definitions 43 | 44 | - *-ie7.css - if you need IE7 support, but still don't wish to put char codes 45 | directly into html 46 | 47 | - *-codes.css and *-ie7-codes.css - if you like to use your own @font-face 48 | rules, but still wish to benefit from css generation. That can be very 49 | convenient for automated asset build systems. When you need to update font - 50 | no need to manually edit files, just override old version with archive 51 | content. See fontello source code for examples. 52 | 53 | - *-embedded.css - basic css file, but with embedded WOFF font, to avoid 54 | CORS issues in Firefox and IE9+, when fonts are hosted on the separate domain. 55 | We strongly recommend to resolve this issue by `Access-Control-Allow-Origin` 56 | server headers. But if you ok with dirty hack - this file is for you. Note, 57 | that data url moved to separate @font-face to avoid problems with 5 |

Library

6 |
7 | Home 8 | Gallery 9 | Installation 10 |
11 | 12 | `; 13 | 14 | 15 | document.getElementById("footer").innerHTML = ` 16 |
17 |

Theme & Website by Fr75s.

18 | 19 | Source Code 20 |
21 | `; 22 | 23 | -------------------------------------------------------------------------------- /assets/SAFELY_REMOVABLE/website/gallery.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | Library 7 | 8 | 9 | 10 | 11 | 12 |
13 |

Gallery

14 | 15 |

Home Page

16 | A screenshot of the home page. 17 | 18 |

Search Page

19 | A screenshot of the search page with the keyboard showing. 20 | 21 |

Feed Page (Accessible within the Search Page)

22 | A screenshot of a video playing in the feed page. 23 | 24 |

Collections Page

25 | A screenshot of the collections page, showing several collections in a grid. 26 | 27 |

Settings

28 | A screenshot of the settings page, showing the localization section. 29 | 30 |

Favorites Section (Customization 1)

31 | A screenshot of the favorite games section shown. The screenshot showcases the light theme as well as rounded game corners. 32 | 33 |

Search Page Games List (Customization 2)

34 | A screenshot of a the search page, this time without the keyboard. The games are presented wider, and there are 4 rows of them on screen. 35 | 36 |

Collections Page Again (Customization 3)

37 | A screenshot of a the collections page. The background is different, the navigation bar is larger, and there is now a clock on the top-left corner. 38 | 39 |

Collections Page Games (Customization 4)

40 | A screenshot inside a collection showing a grid of games. The games are once again presented wider, but there is also the same background as in the previous screenshot, except in light mode. 41 |
42 |
43 | 44 | 45 | 46 | 47 | -------------------------------------------------------------------------------- /assets/SAFELY_REMOVABLE/website/install.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | Library 7 | 8 | 9 | 10 | 11 | 12 |
13 |

Installation

14 | 15 |

Installing this theme is simple, and can be done with the following steps.

16 |

First, download the theme's contents, which can be done by clicking the button below, or by downloading the zip file from the github page.

17 | 18 | Download 19 | 20 |

Next, extract the contents of the .zip file to your themes folder: refer to the official Pegasus documentation for more information as to where exactly the themes folder is on your system.

21 | 22 |

Finally, you may remove the SAFELY_REMOVABLE folder that's in the assets folder within the theme's folder, as it only provides screenshots and other resources not required to run the theme.

23 |
24 |
25 | 26 | 27 | 28 | 29 | -------------------------------------------------------------------------------- /assets/SAFELY_REMOVABLE/website/main.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | Library 7 | 8 | 9 | 10 | 11 | 12 |
13 | 14 | 15 |

Overview

16 |

Library is a clean, modern interface for Pegasus Frontend that aims to provide a useful theme that makes it quick to find and play games. Inspired partly by the Steam Deck's UI, this interface focuses more on displaying box art in organized categories with a minimal amount of text.

17 | 18 |

Library aims to be easy to use once Pegasus itself is set up. While Pegasus Frontend is not the friendliest in terms of configuration, tools are available that can help you to at least get metadata for the theme. 19 | 20 | 21 |

Features

22 |

Customizable

23 |

Library has several toggleable options which allow you to easily modify parts of the theme. Options include a light mode, expanding the game width and more. Of course, you can always customize the QML files; we even provide a guide for some quick modifications to get started.

24 | 25 |

Little Hassle

26 |

Library is a theme that is quite simple to use, making it easy to search through your game library. It also uses little metadata: only the title, box art and another art/screenshot is needed for games to fully function.

27 | 28 |

Advanced

29 |

Library has several advanced features which other themes don't have, such as mouse-based navigation and a virtual keyboard for searching. These advanced features enhance your experience.

30 | 31 | 32 |

Special Thanks

33 |

I referred to other projects throughout the creation of this theme. These projects are listed below.

34 | 35 | 46 | 47 |

I would also like to thank TigraTT-Driver, who has contributed several new features to Library and who has provided the German translation.

48 | 49 |
50 |
51 | 52 | 53 | 54 | 55 | -------------------------------------------------------------------------------- /assets/SAFELY_REMOVABLE/website/styles/Outfit-Variable.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Fr75s/library/dd44cb3c00ca14b1bc8eaadb96f385a09b372984/assets/SAFELY_REMOVABLE/website/styles/Outfit-Variable.ttf -------------------------------------------------------------------------------- /assets/SAFELY_REMOVABLE/website/styles/fonts.css: -------------------------------------------------------------------------------- 1 | @font-face { 2 | font-family: "Outfit"; 3 | src: url("Outfit-Variable.ttf") format("truetype"); 4 | } 5 | -------------------------------------------------------------------------------- /assets/SAFELY_REMOVABLE/website/styles/main.css: -------------------------------------------------------------------------------- 1 | @import "fonts.css"; 2 | 3 | html { 4 | font-size: 18px; 5 | font-family: "Outfit"; 6 | 7 | color: #CCCCCC; 8 | font-weight: 300; 9 | 10 | background-color: #16171A; 11 | 12 | position: relative; 13 | min-height: 100%; 14 | } 15 | 16 | body { 17 | margin: 0 0 200px; /* Last margin is footer spacing + height*/ 18 | } 19 | 20 | header { 21 | margin-bottom: 20px; 22 | background-color: #26282D; 23 | } 24 | 25 | main { 26 | margin: 0 auto; 27 | 28 | width: 800px; 29 | } 30 | 31 | @media screen and (max-width: 1000px) { 32 | main { 33 | width: 80%; 34 | } 35 | } 36 | 37 | footer { 38 | background-color: #16171A; 39 | 40 | position: absolute; 41 | bottom: 0; 42 | width: 100%; 43 | 44 | height: 80px; 45 | 46 | border-style: solid; 47 | border-color: #484858; 48 | border-width: 2px 0px 0px 0px; 49 | } 50 | 51 | 52 | h1, h2, h3 { 53 | color: #FFFFFF; 54 | font-family: "Outfit"; 55 | font-weight: 500; 56 | } 57 | 58 | h1 { font-size: 36px; padding-top: 20px; } 59 | h2 { font-size: 24px; padding-top: 10px; } 60 | h3 { font-size: 18px; padding-top: 5px; } 61 | 62 | p, a { 63 | color: #CCCCCC; 64 | } 65 | 66 | .hlink { 67 | text-decoration: none; 68 | } 69 | 70 | .button { 71 | cursor: pointer; 72 | border: none; 73 | background-color: #212326; 74 | 75 | width: 50%; 76 | text-align: center; 77 | text-decoration: none; 78 | 79 | border-radius: 16px; 80 | 81 | font-family: "Outfit"; 82 | font-size: 36px; 83 | font-weight: 200; 84 | 85 | padding: 20px 40px 20px 40px; 86 | margin: 40px 0px 40px 0px; 87 | color: white; 88 | box-shadow: 0px 0px 8px rgba(0, 0, 0, 0.4); 89 | } 90 | 91 | 92 | .centered { 93 | display: block; 94 | margin-left: auto; 95 | margin-right: auto; 96 | } 97 | 98 | .ci { 99 | cursor: pointer; 100 | } 101 | 102 | .row { 103 | display: flex; 104 | flex-direction: row; 105 | align-items: flex-start; 106 | } 107 | 108 | .edgerow { 109 | justify-content: space-between; 110 | } 111 | 112 | .rowitem { 113 | margin: 10px 30px 10px 0px; 114 | } 115 | 116 | .endblock { 117 | margin: 80px; 118 | } 119 | -------------------------------------------------------------------------------- /assets/audio/accept.wav: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Fr75s/library/dd44cb3c00ca14b1bc8eaadb96f385a09b372984/assets/audio/accept.wav -------------------------------------------------------------------------------- /assets/audio/back.wav: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Fr75s/library/dd44cb3c00ca14b1bc8eaadb96f385a09b372984/assets/audio/back.wav -------------------------------------------------------------------------------- /assets/audio/favorite.wav: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Fr75s/library/dd44cb3c00ca14b1bc8eaadb96f385a09b372984/assets/audio/favorite.wav -------------------------------------------------------------------------------- /assets/audio/game.wav: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Fr75s/library/dd44cb3c00ca14b1bc8eaadb96f385a09b372984/assets/audio/game.wav -------------------------------------------------------------------------------- /assets/audio/nav.wav: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Fr75s/library/dd44cb3c00ca14b1bc8eaadb96f385a09b372984/assets/audio/nav.wav -------------------------------------------------------------------------------- /assets/audio/switchB.wav: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Fr75s/library/dd44cb3c00ca14b1bc8eaadb96f385a09b372984/assets/audio/switchB.wav -------------------------------------------------------------------------------- /assets/audio/switchF.wav: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Fr75s/library/dd44cb3c00ca14b1bc8eaadb96f385a09b372984/assets/audio/switchF.wav -------------------------------------------------------------------------------- /assets/audio/tab.wav: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Fr75s/library/dd44cb3c00ca14b1bc8eaadb96f385a09b372984/assets/audio/tab.wav -------------------------------------------------------------------------------- /assets/audio/type.wav: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Fr75s/library/dd44cb3c00ca14b1bc8eaadb96f385a09b372984/assets/audio/type.wav -------------------------------------------------------------------------------- /assets/backgrounds/dark-1.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Fr75s/library/dd44cb3c00ca14b1bc8eaadb96f385a09b372984/assets/backgrounds/dark-1.jpg -------------------------------------------------------------------------------- /assets/backgrounds/dark-2.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Fr75s/library/dd44cb3c00ca14b1bc8eaadb96f385a09b372984/assets/backgrounds/dark-2.jpg -------------------------------------------------------------------------------- /assets/backgrounds/light-1.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Fr75s/library/dd44cb3c00ca14b1bc8eaadb96f385a09b372984/assets/backgrounds/light-1.jpg -------------------------------------------------------------------------------- /assets/backgrounds/light-2.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Fr75s/library/dd44cb3c00ca14b1bc8eaadb96f385a09b372984/assets/backgrounds/light-2.jpg -------------------------------------------------------------------------------- /assets/font/Gilroy-ExtraBold.otf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Fr75s/library/dd44cb3c00ca14b1bc8eaadb96f385a09b372984/assets/font/Gilroy-ExtraBold.otf -------------------------------------------------------------------------------- /assets/font/Gilroy-Light.otf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Fr75s/library/dd44cb3c00ca14b1bc8eaadb96f385a09b372984/assets/font/Gilroy-Light.otf -------------------------------------------------------------------------------- /assets/font/NotoSansJP-ExtraBold.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Fr75s/library/dd44cb3c00ca14b1bc8eaadb96f385a09b372984/assets/font/NotoSansJP-ExtraBold.ttf -------------------------------------------------------------------------------- /assets/font/NotoSansJP-Light.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Fr75s/library/dd44cb3c00ca14b1bc8eaadb96f385a09b372984/assets/font/NotoSansJP-Light.ttf -------------------------------------------------------------------------------- /assets/font/library-icons-font.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Fr75s/library/dd44cb3c00ca14b1bc8eaadb96f385a09b372984/assets/font/library-icons-font.ttf -------------------------------------------------------------------------------- /assets/logo/banner/3do.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Fr75s/library/dd44cb3c00ca14b1bc8eaadb96f385a09b372984/assets/logo/banner/3do.jpg -------------------------------------------------------------------------------- /assets/logo/banner/3ds.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Fr75s/library/dd44cb3c00ca14b1bc8eaadb96f385a09b372984/assets/logo/banner/3ds.jpg -------------------------------------------------------------------------------- /assets/logo/banner/all.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Fr75s/library/dd44cb3c00ca14b1bc8eaadb96f385a09b372984/assets/logo/banner/all.jpg -------------------------------------------------------------------------------- /assets/logo/banner/amiga.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Fr75s/library/dd44cb3c00ca14b1bc8eaadb96f385a09b372984/assets/logo/banner/amiga.jpg -------------------------------------------------------------------------------- /assets/logo/banner/amstradcpc.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Fr75s/library/dd44cb3c00ca14b1bc8eaadb96f385a09b372984/assets/logo/banner/amstradcpc.jpg -------------------------------------------------------------------------------- /assets/logo/banner/android.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Fr75s/library/dd44cb3c00ca14b1bc8eaadb96f385a09b372984/assets/logo/banner/android.jpg -------------------------------------------------------------------------------- /assets/logo/banner/apple2.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Fr75s/library/dd44cb3c00ca14b1bc8eaadb96f385a09b372984/assets/logo/banner/apple2.jpg -------------------------------------------------------------------------------- /assets/logo/banner/arcade.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Fr75s/library/dd44cb3c00ca14b1bc8eaadb96f385a09b372984/assets/logo/banner/arcade.jpg -------------------------------------------------------------------------------- /assets/logo/banner/atari2600.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Fr75s/library/dd44cb3c00ca14b1bc8eaadb96f385a09b372984/assets/logo/banner/atari2600.jpg -------------------------------------------------------------------------------- /assets/logo/banner/atari5200.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Fr75s/library/dd44cb3c00ca14b1bc8eaadb96f385a09b372984/assets/logo/banner/atari5200.jpg -------------------------------------------------------------------------------- /assets/logo/banner/atari7800.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Fr75s/library/dd44cb3c00ca14b1bc8eaadb96f385a09b372984/assets/logo/banner/atari7800.jpg -------------------------------------------------------------------------------- /assets/logo/banner/atarijaguar.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Fr75s/library/dd44cb3c00ca14b1bc8eaadb96f385a09b372984/assets/logo/banner/atarijaguar.jpg -------------------------------------------------------------------------------- /assets/logo/banner/atarilynx.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Fr75s/library/dd44cb3c00ca14b1bc8eaadb96f385a09b372984/assets/logo/banner/atarilynx.jpg -------------------------------------------------------------------------------- /assets/logo/banner/atarist.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Fr75s/library/dd44cb3c00ca14b1bc8eaadb96f385a09b372984/assets/logo/banner/atarist.jpg -------------------------------------------------------------------------------- /assets/logo/banner/atomiswave.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Fr75s/library/dd44cb3c00ca14b1bc8eaadb96f385a09b372984/assets/logo/banner/atomiswave.jpg -------------------------------------------------------------------------------- /assets/logo/banner/c64.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Fr75s/library/dd44cb3c00ca14b1bc8eaadb96f385a09b372984/assets/logo/banner/c64.jpg -------------------------------------------------------------------------------- /assets/logo/banner/cdi.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Fr75s/library/dd44cb3c00ca14b1bc8eaadb96f385a09b372984/assets/logo/banner/cdi.jpg -------------------------------------------------------------------------------- /assets/logo/banner/colecovision.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Fr75s/library/dd44cb3c00ca14b1bc8eaadb96f385a09b372984/assets/logo/banner/colecovision.jpg -------------------------------------------------------------------------------- /assets/logo/banner/cps1.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Fr75s/library/dd44cb3c00ca14b1bc8eaadb96f385a09b372984/assets/logo/banner/cps1.jpg -------------------------------------------------------------------------------- /assets/logo/banner/cps2.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Fr75s/library/dd44cb3c00ca14b1bc8eaadb96f385a09b372984/assets/logo/banner/cps2.jpg -------------------------------------------------------------------------------- /assets/logo/banner/cps3.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Fr75s/library/dd44cb3c00ca14b1bc8eaadb96f385a09b372984/assets/logo/banner/cps3.jpg -------------------------------------------------------------------------------- /assets/logo/banner/daphne.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Fr75s/library/dd44cb3c00ca14b1bc8eaadb96f385a09b372984/assets/logo/banner/daphne.jpg -------------------------------------------------------------------------------- /assets/logo/banner/dreamcast.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Fr75s/library/dd44cb3c00ca14b1bc8eaadb96f385a09b372984/assets/logo/banner/dreamcast.jpg -------------------------------------------------------------------------------- /assets/logo/banner/empty.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Fr75s/library/dd44cb3c00ca14b1bc8eaadb96f385a09b372984/assets/logo/banner/empty.jpg -------------------------------------------------------------------------------- /assets/logo/banner/fba.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Fr75s/library/dd44cb3c00ca14b1bc8eaadb96f385a09b372984/assets/logo/banner/fba.jpg -------------------------------------------------------------------------------- /assets/logo/banner/fbneo.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Fr75s/library/dd44cb3c00ca14b1bc8eaadb96f385a09b372984/assets/logo/banner/fbneo.jpg -------------------------------------------------------------------------------- /assets/logo/banner/fds.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Fr75s/library/dd44cb3c00ca14b1bc8eaadb96f385a09b372984/assets/logo/banner/fds.jpg -------------------------------------------------------------------------------- /assets/logo/banner/flash.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Fr75s/library/dd44cb3c00ca14b1bc8eaadb96f385a09b372984/assets/logo/banner/flash.jpg -------------------------------------------------------------------------------- /assets/logo/banner/gamegear.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Fr75s/library/dd44cb3c00ca14b1bc8eaadb96f385a09b372984/assets/logo/banner/gamegear.jpg -------------------------------------------------------------------------------- /assets/logo/banner/gb.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Fr75s/library/dd44cb3c00ca14b1bc8eaadb96f385a09b372984/assets/logo/banner/gb.jpg -------------------------------------------------------------------------------- /assets/logo/banner/gba.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Fr75s/library/dd44cb3c00ca14b1bc8eaadb96f385a09b372984/assets/logo/banner/gba.jpg -------------------------------------------------------------------------------- /assets/logo/banner/gbc.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Fr75s/library/dd44cb3c00ca14b1bc8eaadb96f385a09b372984/assets/logo/banner/gbc.jpg -------------------------------------------------------------------------------- /assets/logo/banner/gc.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Fr75s/library/dd44cb3c00ca14b1bc8eaadb96f385a09b372984/assets/logo/banner/gc.jpg -------------------------------------------------------------------------------- /assets/logo/banner/generic.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Fr75s/library/dd44cb3c00ca14b1bc8eaadb96f385a09b372984/assets/logo/banner/generic.png -------------------------------------------------------------------------------- /assets/logo/banner/genesis.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Fr75s/library/dd44cb3c00ca14b1bc8eaadb96f385a09b372984/assets/logo/banner/genesis.jpg -------------------------------------------------------------------------------- /assets/logo/banner/gog.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Fr75s/library/dd44cb3c00ca14b1bc8eaadb96f385a09b372984/assets/logo/banner/gog.jpg -------------------------------------------------------------------------------- /assets/logo/banner/gog_alt.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Fr75s/library/dd44cb3c00ca14b1bc8eaadb96f385a09b372984/assets/logo/banner/gog_alt.jpg -------------------------------------------------------------------------------- /assets/logo/banner/intellivision.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Fr75s/library/dd44cb3c00ca14b1bc8eaadb96f385a09b372984/assets/logo/banner/intellivision.jpg -------------------------------------------------------------------------------- /assets/logo/banner/lutris.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Fr75s/library/dd44cb3c00ca14b1bc8eaadb96f385a09b372984/assets/logo/banner/lutris.jpg -------------------------------------------------------------------------------- /assets/logo/banner/mame.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Fr75s/library/dd44cb3c00ca14b1bc8eaadb96f385a09b372984/assets/logo/banner/mame.jpg -------------------------------------------------------------------------------- /assets/logo/banner/mastersystem.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Fr75s/library/dd44cb3c00ca14b1bc8eaadb96f385a09b372984/assets/logo/banner/mastersystem.jpg -------------------------------------------------------------------------------- /assets/logo/banner/megadrive.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Fr75s/library/dd44cb3c00ca14b1bc8eaadb96f385a09b372984/assets/logo/banner/megadrive.jpg -------------------------------------------------------------------------------- /assets/logo/banner/msx.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Fr75s/library/dd44cb3c00ca14b1bc8eaadb96f385a09b372984/assets/logo/banner/msx.jpg -------------------------------------------------------------------------------- /assets/logo/banner/msx2.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Fr75s/library/dd44cb3c00ca14b1bc8eaadb96f385a09b372984/assets/logo/banner/msx2.jpg -------------------------------------------------------------------------------- /assets/logo/banner/n64.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Fr75s/library/dd44cb3c00ca14b1bc8eaadb96f385a09b372984/assets/logo/banner/n64.jpg -------------------------------------------------------------------------------- /assets/logo/banner/nds.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Fr75s/library/dd44cb3c00ca14b1bc8eaadb96f385a09b372984/assets/logo/banner/nds.jpg -------------------------------------------------------------------------------- /assets/logo/banner/neogeo.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Fr75s/library/dd44cb3c00ca14b1bc8eaadb96f385a09b372984/assets/logo/banner/neogeo.jpg -------------------------------------------------------------------------------- /assets/logo/banner/neogeocd.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Fr75s/library/dd44cb3c00ca14b1bc8eaadb96f385a09b372984/assets/logo/banner/neogeocd.jpg -------------------------------------------------------------------------------- /assets/logo/banner/nes.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Fr75s/library/dd44cb3c00ca14b1bc8eaadb96f385a09b372984/assets/logo/banner/nes.jpg -------------------------------------------------------------------------------- /assets/logo/banner/ngp.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Fr75s/library/dd44cb3c00ca14b1bc8eaadb96f385a09b372984/assets/logo/banner/ngp.jpg -------------------------------------------------------------------------------- /assets/logo/banner/ngpc.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Fr75s/library/dd44cb3c00ca14b1bc8eaadb96f385a09b372984/assets/logo/banner/ngpc.jpg -------------------------------------------------------------------------------- /assets/logo/banner/pc.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Fr75s/library/dd44cb3c00ca14b1bc8eaadb96f385a09b372984/assets/logo/banner/pc.jpg -------------------------------------------------------------------------------- /assets/logo/banner/pcengine.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Fr75s/library/dd44cb3c00ca14b1bc8eaadb96f385a09b372984/assets/logo/banner/pcengine.jpg -------------------------------------------------------------------------------- /assets/logo/banner/pcfx.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Fr75s/library/dd44cb3c00ca14b1bc8eaadb96f385a09b372984/assets/logo/banner/pcfx.jpg -------------------------------------------------------------------------------- /assets/logo/banner/pico8.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Fr75s/library/dd44cb3c00ca14b1bc8eaadb96f385a09b372984/assets/logo/banner/pico8.jpg -------------------------------------------------------------------------------- /assets/logo/banner/ports.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Fr75s/library/dd44cb3c00ca14b1bc8eaadb96f385a09b372984/assets/logo/banner/ports.jpg -------------------------------------------------------------------------------- /assets/logo/banner/ps2.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Fr75s/library/dd44cb3c00ca14b1bc8eaadb96f385a09b372984/assets/logo/banner/ps2.jpg -------------------------------------------------------------------------------- /assets/logo/banner/ps3.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Fr75s/library/dd44cb3c00ca14b1bc8eaadb96f385a09b372984/assets/logo/banner/ps3.jpg -------------------------------------------------------------------------------- /assets/logo/banner/psp.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Fr75s/library/dd44cb3c00ca14b1bc8eaadb96f385a09b372984/assets/logo/banner/psp.jpg -------------------------------------------------------------------------------- /assets/logo/banner/psx.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Fr75s/library/dd44cb3c00ca14b1bc8eaadb96f385a09b372984/assets/logo/banner/psx.jpg -------------------------------------------------------------------------------- /assets/logo/banner/saturn.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Fr75s/library/dd44cb3c00ca14b1bc8eaadb96f385a09b372984/assets/logo/banner/saturn.jpg -------------------------------------------------------------------------------- /assets/logo/banner/scumm.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Fr75s/library/dd44cb3c00ca14b1bc8eaadb96f385a09b372984/assets/logo/banner/scumm.jpg -------------------------------------------------------------------------------- /assets/logo/banner/sega32x.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Fr75s/library/dd44cb3c00ca14b1bc8eaadb96f385a09b372984/assets/logo/banner/sega32x.jpg -------------------------------------------------------------------------------- /assets/logo/banner/segacd.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Fr75s/library/dd44cb3c00ca14b1bc8eaadb96f385a09b372984/assets/logo/banner/segacd.jpg -------------------------------------------------------------------------------- /assets/logo/banner/snes.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Fr75s/library/dd44cb3c00ca14b1bc8eaadb96f385a09b372984/assets/logo/banner/snes.jpg -------------------------------------------------------------------------------- /assets/logo/banner/source-note.txt: -------------------------------------------------------------------------------- 1 | Most of these images are sourced from neoretrō: https://github.com/valsou/neoretro 2 | 3 | steam.jpg is from shinretro: https://github.com/TigraTT-Driver/shinretro 4 | 5 | Finally, android.jpg, cdi.jpg, flash.jpg, lutris.jpg, pc.jpg/ports.jpg, str.jpg, windows.jpg, pico-8.jpg, tic80.jpg and winuwp.jpg were all created from pre-existing images myself. If you're the author of the image and don't like me using it, tell me and I will replace it. 6 | -------------------------------------------------------------------------------- /assets/logo/banner/steam.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Fr75s/library/dd44cb3c00ca14b1bc8eaadb96f385a09b372984/assets/logo/banner/steam.jpg -------------------------------------------------------------------------------- /assets/logo/banner/steam_alt.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Fr75s/library/dd44cb3c00ca14b1bc8eaadb96f385a09b372984/assets/logo/banner/steam_alt.jpg -------------------------------------------------------------------------------- /assets/logo/banner/str.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Fr75s/library/dd44cb3c00ca14b1bc8eaadb96f385a09b372984/assets/logo/banner/str.jpg -------------------------------------------------------------------------------- /assets/logo/banner/switch.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Fr75s/library/dd44cb3c00ca14b1bc8eaadb96f385a09b372984/assets/logo/banner/switch.jpg -------------------------------------------------------------------------------- /assets/logo/banner/tic80.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Fr75s/library/dd44cb3c00ca14b1bc8eaadb96f385a09b372984/assets/logo/banner/tic80.jpg -------------------------------------------------------------------------------- /assets/logo/banner/turbografx16.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Fr75s/library/dd44cb3c00ca14b1bc8eaadb96f385a09b372984/assets/logo/banner/turbografx16.jpg -------------------------------------------------------------------------------- /assets/logo/banner/vectrex.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Fr75s/library/dd44cb3c00ca14b1bc8eaadb96f385a09b372984/assets/logo/banner/vectrex.jpg -------------------------------------------------------------------------------- /assets/logo/banner/virtualboy.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Fr75s/library/dd44cb3c00ca14b1bc8eaadb96f385a09b372984/assets/logo/banner/virtualboy.jpg -------------------------------------------------------------------------------- /assets/logo/banner/wii.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Fr75s/library/dd44cb3c00ca14b1bc8eaadb96f385a09b372984/assets/logo/banner/wii.jpg -------------------------------------------------------------------------------- /assets/logo/banner/wiiu.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Fr75s/library/dd44cb3c00ca14b1bc8eaadb96f385a09b372984/assets/logo/banner/wiiu.jpg -------------------------------------------------------------------------------- /assets/logo/banner/wiiware.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Fr75s/library/dd44cb3c00ca14b1bc8eaadb96f385a09b372984/assets/logo/banner/wiiware.jpg -------------------------------------------------------------------------------- /assets/logo/banner/windows.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Fr75s/library/dd44cb3c00ca14b1bc8eaadb96f385a09b372984/assets/logo/banner/windows.jpg -------------------------------------------------------------------------------- /assets/logo/banner/winuwp.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Fr75s/library/dd44cb3c00ca14b1bc8eaadb96f385a09b372984/assets/logo/banner/winuwp.jpg -------------------------------------------------------------------------------- /assets/logo/banner/zxspectrum.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Fr75s/library/dd44cb3c00ca14b1bc8eaadb96f385a09b372984/assets/logo/banner/zxspectrum.jpg -------------------------------------------------------------------------------- /assets/theme/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Fr75s/library/dd44cb3c00ca14b1bc8eaadb96f385a09b372984/assets/theme/logo.png -------------------------------------------------------------------------------- /assets/theme/logo.svg: -------------------------------------------------------------------------------- 1 | 2 | 14 | 16 | 35 | 39 | 40 | -------------------------------------------------------------------------------- /index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Redirecting... 6 | 7 | 8 |
9 |
10 | 11 |
12 | 13 | 14 | 15 | -------------------------------------------------------------------------------- /theme.cfg: -------------------------------------------------------------------------------- 1 | name: Library 2 | author: Fr75s 3 | version: 1.5.1 4 | summary: A clean theme reminiscent of the Steam Deck 5 | description: A clean, modern, and extremely customizable interface for Pegasus Frontend, inspired by the Steam Deck UI 6 | keywords: 10foot,clean,grid,modern,16:9,16:10 7 | homepage: https://fr75s.github.io/library/assets/SAFELY_REMOVABLE/website/main.html 8 | assets.screenshots: 9 | assets/SAFELY_REMOVABLE/screenshot_1.png 10 | assets/SAFELY_REMOVABLE/screenshot_2.png 11 | assets/SAFELY_REMOVABLE/screenshot_3.png 12 | assets/SAFELY_REMOVABLE/screenshot_4.png 13 | assets/SAFELY_REMOVABLE/screenshot_5.png 14 | assets/SAFELY_REMOVABLE/screenshot_6.png 15 | assets/SAFELY_REMOVABLE/screenshot_7.png 16 | assets/SAFELY_REMOVABLE/screenshot_8.png 17 | assets/SAFELY_REMOVABLE/screenshot_9.png 18 | --------------------------------------------------------------------------------