Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Binary file added resources/images/logo-crt.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
3 changes: 3 additions & 0 deletions rust/launcher/.qmlls.ini
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
[General]
buildDir="/tmp/zaparoo-target/cxxqt/qml_modules"
no-cmake-calls=true
2 changes: 1 addition & 1 deletion scripts/run-macos-mister-core.sh
Original file line number Diff line number Diff line change
Expand Up @@ -17,5 +17,5 @@ fi

export ZAPAROO_CORE_ENDPOINT="ws://192.168.1.176:7497/api/v0.1"
export ZAPAROO_CRT_PREVIEW_SCALE=3
exec "${FRONTEND}"
exec "${FRONTEND}" --crt
# exec "${FRONTEND}" --crt
14 changes: 12 additions & 2 deletions src/ui/app/MainLayout.qml
Original file line number Diff line number Diff line change
Expand Up @@ -287,7 +287,7 @@ ApplicationWindow {

readonly property string recentsScreenState: Browse.RecentsModel.loading ? "loading" : ((Browse.RecentsModel.error_message ?? "") !== "" ? "error" : (Browse.RecentsModel.count === 0 ? "empty" : "ready"))
readonly property bool _crtGridBrowseLayout: root.crtNativePath && Browse.Settings.current_browse_layout !== "list"
readonly property var _browseTileLayout: root._crtGridBrowseLayout ? BrowseLayouts.crtTile : BrowseLayouts.defaultTile
readonly property var _browseTileLayout: root.crtNativePath ? BrowseLayouts.crtTile : BrowseLayouts.defaultTile
readonly property var _contextMenuLayout: root.crtNativePath ? BrowseLayouts.crtTile : BrowseLayouts.defaultTile
readonly property string _crtGamesHeaderTitle: {
const sid = Browse.GamesModel.current_system_id;
Expand All @@ -297,12 +297,21 @@ ApplicationWindow {
return idx >= 0 ? Browse.SystemsModel.system_name_at(idx) : sid;
}
readonly property string browseHeaderTitle: {
if (!root._crtGridBrowseLayout)
if (!root.crtNativePath)
return "";
if (Browse.Settings.current_browse_layout === "list")
return "";
if (root.activeScreen === root.screenSystems)
return Browse.SystemsModel.current_category;
if (root.activeScreen === root.screenGames)
return root._crtGamesHeaderTitle;
if (root.activeScreen === root.screenFavorites)
return qsTr("Favorites");
if (root.activeScreen === root.screenRecents)
return qsTr("Recently Played");
return "";
}
readonly property string browseHeaderProgressText: {
return "";
}

Expand Down Expand Up @@ -427,6 +436,7 @@ ApplicationWindow {
anchors.topMargin: Sizing.headerTopMargin
layoutProfile: root._browseTileLayout
browseTitle: root.browseHeaderTitle
browseProgressText: root.browseHeaderProgressText
z: 200
}

Expand Down
50 changes: 32 additions & 18 deletions src/ui/components/BrowseDetailPane.qml
Original file line number Diff line number Diff line change
Expand Up @@ -21,24 +21,37 @@ Item {
property bool detailSuppressed: false
property bool showChrome: true
property string loadingText: qsTr("Loading…")
property var layoutProfile: null

readonly property int _cardPaddingX: Sizing.pctW(2)
readonly property int _cardPaddingY: Sizing.pctH(2)
readonly property int _cardPaddingLeft: root.layoutProfile && root.layoutProfile.detailPanePaddingLeft !== undefined ? root.layoutProfile.detailPanePaddingLeft : Sizing.pctW(2)
readonly property int _cardPaddingRight: root.layoutProfile && root.layoutProfile.detailPanePaddingRight !== undefined ? root.layoutProfile.detailPanePaddingRight : Sizing.pctW(2)
readonly property int _cardPaddingTop: root.layoutProfile && root.layoutProfile.detailPanePaddingTop !== undefined ? root.layoutProfile.detailPanePaddingTop : Sizing.pctH(2)
readonly property int _cardPaddingBottom: root.layoutProfile && root.layoutProfile.detailPanePaddingBottom !== undefined ? root.layoutProfile.detailPanePaddingBottom : Sizing.pctH(2)
readonly property int _carouselGutter: (canPreviousImage || canNextImage) ? Sizing.pctW(4) : 0
property int _labelColumnWidth: 0
readonly property int _tagTextSize: Sizing.fontSize(2.2)
readonly property int _tagLabelGap: Sizing.pctW(1.4)
readonly property var _detailRows: _parseDetailTags(detailTags)
readonly property int _tagRowCount: _detailRows.length
readonly property int _tagRowHeight: Sizing.pctH(3)
readonly property int _tagRowSpacing: Sizing.pctH(0.55)
readonly property int _tagRowHeight: root.layoutProfile && root.layoutProfile.detailTagRowHeight !== undefined ? root.layoutProfile.detailTagRowHeight : Sizing.pctH(3)
readonly property int _tagRowSpacing: root.layoutProfile && root.layoutProfile.detailTagRowSpacing !== undefined ? root.layoutProfile.detailTagRowSpacing : Sizing.pctH(0.55)
readonly property int _metadataNaturalHeight: _tagRowCount <= 0 ? 0 : (_tagRowCount * _tagRowHeight) + ((_tagRowCount - 1) * _tagRowSpacing)
readonly property int _compactDetailHeight: Math.min(Sizing.px(content.height * 0.38), _metadataNaturalHeight)
readonly property bool _coverPending: coverKey === "icons/Loading"
readonly property url _coverSource: _coverPending ? "" : Resources.coverUrl(coverKey)
readonly property bool _paneLoading: root.loading
readonly property bool _detailVisible: !root._paneLoading && !root.detailSuppressed
readonly property bool _suppressedPlaceholderCover: root.detailSuppressed && coverKey.startsWith("icons/") && root._coverSource !== ""
readonly property int _metadataYOffset: root.layoutProfile && root.layoutProfile.detailMetadataYOffset !== undefined ? root.layoutProfile.detailMetadataYOffset : 0
readonly property int _metadataExtraHeight: root.layoutProfile && root.layoutProfile.detailMetadataExtraHeight !== undefined ? root.layoutProfile.detailMetadataExtraHeight : 0
readonly property int _metadataLeftInset: root.layoutProfile && root.layoutProfile.detailMetadataLeftInset !== undefined ? root.layoutProfile.detailMetadataLeftInset : 0
readonly property int _metadataRightInset: root.layoutProfile && root.layoutProfile.detailMetadataRightInset !== undefined ? root.layoutProfile.detailMetadataRightInset : 0
readonly property int _imageXOffset: root.layoutProfile && root.layoutProfile.detailImageXOffset !== undefined ? root.layoutProfile.detailImageXOffset : 0
readonly property int _imageLeftInset: root.layoutProfile && root.layoutProfile.detailImageLeftInset !== undefined ? root.layoutProfile.detailImageLeftInset : 0
readonly property int _imageRightInset: root.layoutProfile && root.layoutProfile.detailImageRightInset !== undefined ? root.layoutProfile.detailImageRightInset : 0
readonly property int _imageExtraWidth: root.layoutProfile && root.layoutProfile.detailImageExtraWidth !== undefined ? root.layoutProfile.detailImageExtraWidth : 0
readonly property int _imageExtraHeight: root.layoutProfile && root.layoutProfile.detailImageExtraHeight !== undefined ? root.layoutProfile.detailImageExtraHeight : 0
readonly property int _imageBottomGap: root.layoutProfile && root.layoutProfile.detailImageBottomGap !== undefined ? root.layoutProfile.detailImageBottomGap : 0

onDetailTagsChanged: root._labelColumnWidth = 0

Expand Down Expand Up @@ -91,23 +104,24 @@ Item {
id: content

anchors.fill: parent
anchors.leftMargin: root._cardPaddingX
anchors.rightMargin: root._cardPaddingX
anchors.topMargin: root._cardPaddingY
anchors.bottomMargin: root._cardPaddingY
anchors.leftMargin: root._cardPaddingLeft
anchors.rightMargin: root._cardPaddingRight
anchors.topMargin: root._cardPaddingTop
anchors.bottomMargin: root._cardPaddingBottom
clip: true

Item {
id: imageSlot

readonly property int availableWidth: Math.max(0, parent.width - (2 * root._carouselGutter))
readonly property int availableHeight: Math.max(0, root.showTitle ? Sizing.px(parent.height * 0.48) : detailBody.y - Sizing.pctH(1))
readonly property int slotSize: Math.min(availableWidth, availableHeight)
readonly property int availableWidth: Math.max(0, parent.width - root._imageLeftInset - root._imageRightInset - (2 * root._carouselGutter))
readonly property int availableHeight: Math.max(0, root.showTitle ? Sizing.px(parent.height * 0.48) : detailBody.y - root._imageBottomGap)
readonly property int slotWidth: Math.min(parent.width - root._imageLeftInset - root._imageRightInset, availableWidth + root._imageExtraWidth)
readonly property int slotHeight: Math.min(parent.height, Math.min(availableWidth, availableHeight) + root._imageExtraHeight)

x: root._carouselGutter + Sizing.center(availableWidth, width)
x: root._imageLeftInset + root._carouselGutter + root._imageXOffset
anchors.top: parent.top
width: slotSize
height: slotSize
width: Math.max(0, slotWidth)
height: slotHeight

Image {
id: cover
Expand Down Expand Up @@ -181,10 +195,10 @@ Item {

readonly property int _bodyY: Math.round(root.showTitle ? (titleText.visible ? titleText.y + titleText.height : imageSlot.y + imageSlot.height) + Sizing.pctH(2) : parent.height - height)

x: 0
y: _bodyY
width: parent.width
height: root.showTitle ? Math.round(Math.max(0, parent.height - _bodyY)) : root._compactDetailHeight
x: root._metadataLeftInset
y: _bodyY + root._metadataYOffset
width: Math.max(0, parent.width - root._metadataLeftInset - root._metadataRightInset)
height: root.showTitle ? Math.round(Math.max(0, parent.height - y + root._metadataExtraHeight)) : root._compactDetailHeight
clip: true

Column {
Expand Down
78 changes: 46 additions & 32 deletions src/ui/components/BrowseList.qml
Original file line number Diff line number Diff line change
Expand Up @@ -17,22 +17,34 @@ Item {
property int targetVisibleRowCount: 0
property bool showFileStem: false
property bool showChrome: true
property var layoutProfile: null
readonly property int itemCount: listView.count
readonly property int totalItems: totalItemsOverride >= 0 ? totalItemsOverride : itemCount
readonly property int cardPaddingX: Sizing.pctW(2)
readonly property int cardPaddingY: Sizing.pctH(2)
readonly property int rowSpacing: Sizing.pctH(0.7)
readonly property int contentHeight: Math.max(0, height - (2 * cardPaddingY))
readonly property int rowHeight: targetVisibleRowCount > 0 ? Math.max(Sizing.pctH(3), Math.floor((contentHeight - (rowSpacing * (targetVisibleRowCount - 1))) / targetVisibleRowCount)) : Sizing.pctH(6)
readonly property int _selectionRadius: root.layoutProfile ? root.layoutProfile.tileCornerRadius : Sizing.cornerRadius
readonly property int cardPaddingLeft: root.layoutProfile ? root.layoutProfile.listCardPaddingLeft : Sizing.pctW(2)
readonly property int cardPaddingRight: root.layoutProfile ? root.layoutProfile.listCardPaddingRight : Sizing.pctW(2)
readonly property int cardPaddingTop: root.layoutProfile ? root.layoutProfile.listCardPaddingTop : Sizing.pctH(2)
readonly property int cardPaddingBottom: root.layoutProfile ? root.layoutProfile.listCardPaddingBottom : Sizing.pctH(2)
readonly property int rowSpacing: root.layoutProfile ? root.layoutProfile.listRowSpacing : Sizing.pctH(0.7)
readonly property int contentHeight: Math.max(0, height - cardPaddingTop - cardPaddingBottom)
readonly property int rowHeight: root.layoutProfile && root.layoutProfile.listRowHeight > 0 ? root.layoutProfile.listRowHeight : (targetVisibleRowCount > 0 ? Math.max(Sizing.pctH(3), Math.floor((contentHeight - (rowSpacing * (targetVisibleRowCount - 1))) / targetVisibleRowCount)) : Sizing.pctH(6))
readonly property int rowStride: rowHeight + rowSpacing
readonly property int visibleRowCount: targetVisibleRowCount > 0 ? targetVisibleRowCount : Math.max(1, Math.floor((contentHeight + rowSpacing) / rowStride))
readonly property int _centerSlot: Math.max(0, Math.floor((visibleRowCount - 1) / 2))
readonly property int _centerSlot: root.layoutProfile && root.layoutProfile.listCenterSlot >= 0 ? Math.max(0, Math.min(visibleRowCount - 1, root.layoutProfile.listCenterSlot)) : Math.max(0, Math.floor((visibleRowCount - 1) / 2))
readonly property int _maxViewTopIndex: Math.max(0, itemCount - visibleRowCount)
readonly property int _viewTopIndex: Math.max(0, Math.min(_maxViewTopIndex, currentIndex - _centerSlot))
readonly property int _targetContentY: _viewTopIndex * rowStride
readonly property int _maxScrollTopIndex: Math.max(0, totalItems - visibleRowCount)
readonly property int _gutterWidth: Sizing.pctW(3)
readonly property int _gutterGap: Sizing.pctW(1.5)
readonly property int _gutterWidth: root.layoutProfile ? root.layoutProfile.gridGutterWidth : Sizing.pctW(3)
readonly property int _gutterGap: root.layoutProfile && root.layoutProfile.listScrollbarGap !== undefined ? root.layoutProfile.listScrollbarGap : (root.layoutProfile ? root.layoutProfile.gridGutterGap : Sizing.pctW(1.5))
readonly property int _scrollThumbWidth: root.layoutProfile ? root.layoutProfile.scrollThumbWidth : Sizing.pctW(1.2)
readonly property int _scrollThumbRightInset: root.layoutProfile ? root.layoutProfile.scrollThumbRightInset : 0
readonly property bool _scrollThumbRightAligned: root.layoutProfile && root.layoutProfile.scrollThumbRightAligned !== undefined ? root.layoutProfile.scrollThumbRightAligned : false
readonly property int _scrollArrowSize: root.layoutProfile ? root.layoutProfile.scrollArrowSize : Math.min(root._gutterWidth, Sizing.pctH(4))
readonly property int _selectionAccentWidth: root.layoutProfile && root.layoutProfile.listSelectionAccentWidth !== undefined ? root.layoutProfile.listSelectionAccentWidth : Sizing.pctW(0.45)
readonly property int _rowTextLeftPadding: root.layoutProfile ? root.layoutProfile.listRowTextLeftPadding : Sizing.pctW(1.6)
readonly property int _rowTextRightPadding: root.layoutProfile ? root.layoutProfile.listRowTextRightPadding : Sizing.pctW(1.6)
readonly property int _favoriteRightPadding: root.layoutProfile ? root.layoutProfile.listFavoriteRightPadding : Sizing.pctW(1.6)

signal itemHovered(int index)
signal itemClicked(int index)
Expand Down Expand Up @@ -87,13 +99,13 @@ Item {
id: listView

anchors.left: parent.left
anchors.leftMargin: root.cardPaddingX
anchors.leftMargin: root.cardPaddingLeft
anchors.top: parent.top
anchors.topMargin: root.cardPaddingY
anchors.topMargin: root.cardPaddingTop
anchors.bottom: parent.bottom
anchors.bottomMargin: root.cardPaddingY
anchors.bottomMargin: root.cardPaddingBottom
anchors.right: parent.right
anchors.rightMargin: root.totalItems > root.visibleRowCount ? root._gutterWidth + root._gutterGap + root.cardPaddingX : root.cardPaddingX
anchors.rightMargin: root.totalItems > root.visibleRowCount ? root._gutterWidth + root._gutterGap + root.cardPaddingRight : root.cardPaddingRight
model: root.model
currentIndex: root.currentIndex
contentY: Math.min(root._targetContentY, Math.max(0, contentHeight - height))
Expand Down Expand Up @@ -139,14 +151,14 @@ Item {
Rectangle {
anchors.fill: parent
color: Theme.selectionSurface
radius: Sizing.cornerRadius
radius: root._selectionRadius
}

Rectangle {
anchors.left: parent.left
anchors.top: parent.top
anchors.bottom: parent.bottom
width: Sizing.cornerRadius
width: root._selectionRadius
color: Theme.selectionSurface
}
}
Expand All @@ -155,17 +167,17 @@ Item {
anchors.left: parent.left
anchors.top: parent.top
anchors.bottom: parent.bottom
width: Sizing.pctW(0.45)
width: root._selectionAccentWidth
color: Theme.accent
visible: row.selected
radius: Math.max(0, Sizing.px(width / 3))
}

Text {
anchors.left: parent.left
anchors.leftMargin: Sizing.pctW(1.6)
anchors.leftMargin: root._rowTextLeftPadding
anchors.right: parent.right
anchors.rightMargin: row.favorite !== 0 ? Sizing.pctW(5.2) : Sizing.pctW(1.6)
anchors.rightMargin: row.favorite !== 0 ? root._favoriteRightPadding + Sizing.pctH(3.2) + root._rowTextRightPadding : root._rowTextRightPadding
anchors.verticalCenter: parent.verticalCenter
text: root.showFileStem && row.fileStem !== "" ? row.fileStem : row.name
color: row.selected ? Theme.textPrimary : Theme.textLabel
Expand All @@ -178,7 +190,7 @@ Item {

Image {
anchors.right: parent.right
anchors.rightMargin: Sizing.pctW(1.6)
anchors.rightMargin: root._favoriteRightPadding
anchors.verticalCenter: parent.verticalCenter
width: Sizing.pctH(3.2)
height: width
Expand Down Expand Up @@ -214,21 +226,19 @@ Item {
id: scrollGutter

anchors.right: parent.right
anchors.rightMargin: root.cardPaddingX
anchors.rightMargin: root.cardPaddingRight
anchors.top: parent.top
anchors.topMargin: root.cardPaddingY
anchors.topMargin: root.cardPaddingTop
anchors.bottom: parent.bottom
anchors.bottomMargin: root.cardPaddingY
anchors.bottomMargin: root.cardPaddingBottom
width: root._gutterWidth
visible: root.totalItems > root.visibleRowCount

readonly property int arrowSize: Math.min(width, Sizing.pctH(4))

Image {
id: upArrow
source: Resources.iconUrl("ScrollUp")
width: scrollGutter.arrowSize
height: scrollGutter.arrowSize
width: root._scrollArrowSize
height: root._scrollArrowSize
anchors.top: parent.top
anchors.horizontalCenter: parent.horizontalCenter
fillMode: Image.PreserveAspectFit
Expand All @@ -247,8 +257,8 @@ Item {
Image {
id: downArrow
source: Resources.iconUrl("ScrollDown")
width: scrollGutter.arrowSize
height: scrollGutter.arrowSize
width: root._scrollArrowSize
height: root._scrollArrowSize
anchors.bottom: parent.bottom
anchors.horizontalCenter: parent.horizontalCenter
fillMode: Image.PreserveAspectFit
Expand All @@ -267,20 +277,24 @@ Item {
Item {
id: scrollRegion
anchors.top: parent.top
anchors.topMargin: scrollGutter.arrowSize + Sizing.pctH(1)
anchors.topMargin: root._scrollArrowSize + Sizing.pctH(1)
anchors.bottom: parent.bottom
anchors.bottomMargin: scrollGutter.arrowSize + Sizing.pctH(1)
anchors.horizontalCenter: parent.horizontalCenter
anchors.bottomMargin: root._scrollArrowSize + Sizing.pctH(1)
anchors.right: root._scrollThumbRightAligned ? parent.right : undefined
anchors.rightMargin: root._scrollThumbRightAligned ? root._scrollThumbRightInset : 0
anchors.horizontalCenter: root._scrollThumbRightAligned ? undefined : parent.horizontalCenter
width: root._scrollThumbWidth

readonly property int _minThumbHeight: Sizing.pctH(4)
readonly property int _thumbHeight: root.totalItems <= 0 ? 0 : Math.min(scrollRegion.height, Math.max(_minThumbHeight, Math.round(scrollRegion.height * root.visibleRowCount / root.totalItems)))
readonly property int _thumbY: root._maxScrollTopIndex <= 0 ? 0 : Sizing.px((root._viewTopIndex / root._maxScrollTopIndex) * (scrollRegion.height - _thumbHeight))

Rectangle {
id: scrollThumb
width: Sizing.pctW(1.2)
width: root._scrollThumbWidth
height: scrollRegion._thumbHeight
anchors.horizontalCenter: parent.horizontalCenter
anchors.right: root._scrollThumbRightAligned ? parent.right : undefined
anchors.horizontalCenter: root._scrollThumbRightAligned ? undefined : parent.horizontalCenter
y: scrollRegion._thumbY
color: Theme.textPrimary
radius: Sizing.half(width)
Expand Down
Loading
Loading