mirror of
https://github.com/AvengeMedia/DankMaterialShell.git
synced 2026-10-17 00:34:01 -04:00
feat(control center): add fractional step sizes to pill widgets
This commit is contained in:
@@ -1,7 +1,8 @@
|
||||
function packCells(cards, order, columns, isAvailable) {
|
||||
function packCells(cards, order, columns, isAvailable, step = 1) {
|
||||
const steps = Math.round(columns / step);
|
||||
const cells = [];
|
||||
const heights = [];
|
||||
for (let c = 0; c < columns; c++)
|
||||
for (let c = 0; c < steps; c++)
|
||||
heights.push(0);
|
||||
let rows = 0;
|
||||
|
||||
@@ -15,11 +16,11 @@ function packCells(cards, order, columns, isAvailable) {
|
||||
continue;
|
||||
}
|
||||
|
||||
const w = Math.max(1, Math.min(columns, card.w || 1));
|
||||
const h = Math.max(1, card.h || 1);
|
||||
const w = Math.max(1, Math.min(steps, Math.round((card.w || 1) / step)));
|
||||
const h = Math.max(1, Math.round((card.h || 1) / step));
|
||||
let bestX = 0;
|
||||
let bestY = Infinity;
|
||||
for (let x = 0; x + w <= columns; x++) {
|
||||
for (let x = 0; x + w <= steps; x++) {
|
||||
let y = 0;
|
||||
for (let c = x; c < x + w; c++)
|
||||
y = Math.max(y, heights[c]);
|
||||
@@ -32,21 +33,21 @@ function packCells(cards, order, columns, isAvailable) {
|
||||
heights[c] = bestY + h;
|
||||
rows = Math.max(rows, bestY + h);
|
||||
cells[sourceIndex] = {
|
||||
"col": bestX,
|
||||
"row": bestY,
|
||||
"cols": w,
|
||||
"rows": h
|
||||
"col": bestX * step,
|
||||
"row": bestY * step,
|
||||
"cols": w * step,
|
||||
"rows": h * step
|
||||
};
|
||||
}
|
||||
|
||||
return {
|
||||
"cells": cells,
|
||||
"rows": rows
|
||||
"rows": rows * step
|
||||
};
|
||||
}
|
||||
|
||||
function packCards(cards, order, columns, width, gap, rowUnit, mirror, isAvailable) {
|
||||
const packed = packCells(cards, order, columns, isAvailable);
|
||||
function packCards(cards, order, columns, width, gap, rowUnit, mirror, isAvailable, step = 1) {
|
||||
const packed = packCells(cards, order, columns, isAvailable, step);
|
||||
const colW = (width - gap * (columns - 1)) / columns;
|
||||
const slots = packed.cells.map(cell => {
|
||||
if (!cell)
|
||||
@@ -160,8 +161,8 @@ function crossGap(a, aSize, b, bSize) {
|
||||
return Math.max(0, b - (a + aSize), a - (b + bSize));
|
||||
}
|
||||
|
||||
function dimension(value, minimum, maximum, fallback) {
|
||||
function dimension(value, minimum, maximum, fallback, step = 1) {
|
||||
const min = minimum ?? 1;
|
||||
const max = Math.max(min, maximum ?? fallback ?? min);
|
||||
return Math.max(min, Math.min(max, Number.isInteger(value) ? value : (fallback ?? min)));
|
||||
return Math.max(min, Math.min(max, typeof value === "number" && Number.isInteger(value / step) ? value : (fallback ?? min)));
|
||||
}
|
||||
|
||||
@@ -10,6 +10,7 @@ Singleton {
|
||||
readonly property int minimumColumns: 6
|
||||
readonly property real sheetPadding: PopoutMetrics.contentPadding
|
||||
readonly property real columnWidth: tileHeight
|
||||
readonly property real gridStep: 0.5
|
||||
property int columnPreview: 0
|
||||
readonly property int gridColumns: columnPreview > 0 ? columnPreview : clampColumns(SettingsData.controlCenterColumns)
|
||||
readonly property real sheetWidth: sheetWidthFor(gridColumns)
|
||||
|
||||
@@ -27,7 +27,7 @@ DankEditableGrid {
|
||||
readonly property CcTileSlot draggingSlot: tileRepeater.itemAt(draggingSourceIndex) as CcTileSlot
|
||||
|
||||
sourceItems: (SettingsData.controlCenterWidgets || []).map(widget => Object.assign({}, widget, WidgetUtils.clampSize(widget, Infinity)))
|
||||
slotLayout: GridUtils.packCards(layoutItems.map(widget => Object.assign({}, widget, WidgetUtils.clampSize(widget, columns, maximumRows))), visualOrder, columns, width, CcMetrics.gridGap, cellWidth - CcMetrics.gridGap, I18n.isRtl)
|
||||
slotLayout: GridUtils.packCards(layoutItems.map(widget => Object.assign({}, widget, WidgetUtils.clampSize(widget, columns, maximumRows))), visualOrder, columns, width, CcMetrics.gridGap, cellWidth - CcMetrics.gridGap, I18n.isRtl, null, CcMetrics.gridStep)
|
||||
placeholderRadius: draggingSlot?.tileItem?.bodyRadius ?? Theme.fullRadius(width, CcMetrics.tileHeight)
|
||||
|
||||
onReorderCommitted: items => model.reorderWidgets(items)
|
||||
|
||||
@@ -10,8 +10,8 @@ DankEditableGridSlot {
|
||||
|
||||
readonly property var widgetData: JSON.parse(json)
|
||||
readonly property var sizeSpec: WidgetUtils.sizeSpec(widgetData.id || "", grid.columns, grid.maximumRows)
|
||||
readonly property int cols: slot?.cols ?? 1
|
||||
readonly property int rows: slot?.rows ?? 1
|
||||
readonly property real cols: slot?.cols ?? 1
|
||||
readonly property real rows: slot?.rows ?? 1
|
||||
readonly property bool compact: cols <= 2 && rows === 1
|
||||
readonly property var tileItem: tileLoader.item
|
||||
|
||||
@@ -22,10 +22,11 @@ DankEditableGridSlot {
|
||||
}
|
||||
|
||||
onResizeRequested: (requestedWidth, requestedHeight) => {
|
||||
let width = GridUtils.dimension(Math.round((requestedWidth + CcMetrics.gridGap) / grid.cellWidth), sizeSpec.minW, sizeSpec.maxW, sizeSpec.w);
|
||||
let height = GridUtils.dimension(Math.round((requestedHeight + CcMetrics.gridGap) / grid.cellWidth), sizeSpec.minH, sizeSpec.maxH, sizeSpec.h);
|
||||
const step = sizeSpec.step;
|
||||
let width = GridUtils.dimension(Math.round((requestedWidth + CcMetrics.gridGap) / grid.cellWidth / step) * step, sizeSpec.minW, sizeSpec.maxW, sizeSpec.w, step);
|
||||
let height = GridUtils.dimension(Math.round((requestedHeight + CcMetrics.gridGap) / grid.cellWidth / step) * step, sizeSpec.minH, sizeSpec.maxH, sizeSpec.h, step);
|
||||
const current = WidgetUtils.clampSize(widgetData, grid.columns, grid.maximumRows);
|
||||
if (WidgetUtils.isSliderWidget(widgetData.id) && width === 1 && height === 1) {
|
||||
if (WidgetUtils.isSliderWidget(widgetData.id) && width < 2 && height < 2) {
|
||||
if (width !== current.w && sizeSpec.maxH > 1)
|
||||
height = 2;
|
||||
else
|
||||
|
||||
@@ -14,8 +14,8 @@ Item {
|
||||
property var host: null
|
||||
property bool live: true
|
||||
property bool interactive: true
|
||||
property int columns: 4
|
||||
property int rows: 1
|
||||
property real columns: 4
|
||||
property real rows: 1
|
||||
property bool compact: columns <= 2 && rows === 1
|
||||
property string iconName: ""
|
||||
property string iconLabel: ""
|
||||
|
||||
@@ -17,8 +17,8 @@ Item {
|
||||
property string title: ""
|
||||
property string subtitle: ""
|
||||
property bool active: false
|
||||
property int columns: 4
|
||||
property int rows: 1
|
||||
property real columns: 4
|
||||
property real rows: 1
|
||||
property bool compact: columns <= 2 && rows === 1
|
||||
property bool toggle: !opensPage
|
||||
property Component expandedContent: null
|
||||
|
||||
@@ -4,8 +4,8 @@ import qs.Common
|
||||
Item {
|
||||
property CcTile tile: null
|
||||
readonly property bool live: tile?.live ?? false
|
||||
readonly property int columns: tile?.columns ?? 4
|
||||
readonly property int rows: tile?.rows ?? 1
|
||||
readonly property real columns: tile?.columns ?? 4
|
||||
readonly property real rows: tile?.rows ?? 1
|
||||
readonly property color contentColor: tile?.contentColor ?? Theme.surfaceText
|
||||
readonly property color subtitleColor: tile?.subtitleColor ?? Theme.surfaceVariantText
|
||||
}
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
.import qs.Common as Common
|
||||
.import qs.Modules.ControlCenter as ControlCenter
|
||||
.import "../../../Common/GridLayout.js" as GridLayout
|
||||
|
||||
function isSliderWidget(id) {
|
||||
@@ -12,17 +13,18 @@ function sizeSpec(id, columns, rows = Infinity) {
|
||||
"minW": 1,
|
||||
"maxW": columns,
|
||||
"minH": 1,
|
||||
"maxH": rows
|
||||
"maxH": rows,
|
||||
"step": ControlCenter.CcMetrics.gridStep
|
||||
};
|
||||
}
|
||||
|
||||
function clampSize(widget, columns, rows = Infinity) {
|
||||
const spec = sizeSpec(widget.id || "", columns, rows);
|
||||
const size = {
|
||||
"w": GridLayout.dimension(widget.w, spec.minW, spec.maxW, spec.w),
|
||||
"h": GridLayout.dimension(widget.h, spec.minH, spec.maxH, spec.h)
|
||||
"w": GridLayout.dimension(widget.w, spec.minW, spec.maxW, spec.w, spec.step),
|
||||
"h": GridLayout.dimension(widget.h, spec.minH, spec.maxH, spec.h, spec.step)
|
||||
};
|
||||
if (!isSliderWidget(widget.id) || size.w > 1 || size.h > 1)
|
||||
if (!isSliderWidget(widget.id) || size.w >= 2 || size.h >= 2)
|
||||
return size;
|
||||
if (rows > 1)
|
||||
return {
|
||||
|
||||
@@ -209,6 +209,23 @@ ShellRoot {
|
||||
});
|
||||
grid.commitSize();
|
||||
check(SettingsData.controlCenterWidgets[1].w === 6 && SettingsData.controlCenterWidgets[1].h === 12, "width edits preserve the saved height on a smaller screen");
|
||||
grid.previewSize(1, {
|
||||
w: 2.5
|
||||
});
|
||||
grid.commitSize();
|
||||
grid.previewSize(1, {
|
||||
h: 1.5
|
||||
});
|
||||
grid.commitSize();
|
||||
const half = grid.slotLayout.slots[1];
|
||||
const cell = grid.cellWidth - CcMetrics.gridGap;
|
||||
check(SettingsData.controlCenterWidgets[1].w === 2.5 && SettingsData.controlCenterWidgets[1].h === 1.5 && half.cols === 2.5 && half.rows === 1.5, "half steps are saved on both axes");
|
||||
check(Math.abs(half.w - (cell * 2.5 + CcMetrics.gridGap * 1.5)) < 0.01 && Math.abs(half.h - (cell * 1.5 + CcMetrics.gridGap * 0.5)) < 0.01, "half spans pack at half pitch");
|
||||
check(WidgetUtils.clampSize({
|
||||
id: "volumeSlider",
|
||||
w: 1.5,
|
||||
h: 1
|
||||
}, 8, 1).w === 2, "sliders under two cells on both axes keep a usable track");
|
||||
check(WidgetUtils.clampSize({
|
||||
id: "volumeSlider",
|
||||
w: 1,
|
||||
@@ -230,6 +247,9 @@ ShellRoot {
|
||||
sliderSlot.resizeRequested(grid.cellWidth - CcMetrics.gridGap, grid.cellWidth - CcMetrics.gridGap);
|
||||
grid.commitSize();
|
||||
check(SettingsData.controlCenterWidgets[0].w === 2 && SettingsData.controlCenterWidgets[0].h === 1, "shortening a slider retains a usable strip layout");
|
||||
sliderSlot.resizeRequested(grid.cellWidth * 3.5 - CcMetrics.gridGap, grid.cellWidth - CcMetrics.gridGap);
|
||||
grid.commitSize();
|
||||
check(SettingsData.controlCenterWidgets[0].w === 3.5 && sliderSlot.tileItem.columns === 3.5, "resizing snaps to half columns");
|
||||
grid.destroy();
|
||||
wait(0);
|
||||
const tile = tileComponent.createObject(scene);
|
||||
|
||||
Reference in New Issue
Block a user