diff --git a/companion/lib/Surface/Controller.js b/companion/lib/Surface/Controller.js
index 4cc0840ef5..b12e91d18f 100644
--- a/companion/lib/Surface/Controller.js
+++ b/companion/lib/Surface/Controller.js
@@ -672,6 +672,9 @@ class SurfaceController extends CoreBase {
isConnected: !!surfaceHandler,
displayName: getSurfaceName(config, id),
location: null,
+
+ size: config?.gridSize || null,
+ offset: { columns: config?.xOffset ?? 0, rows: config?.yOffset ?? 0 },
}
if (surfaceHandler) {
diff --git a/shared-lib/lib/Model/Surfaces.ts b/shared-lib/lib/Model/Surfaces.ts
index 173195b170..6890e28b39 100644
--- a/shared-lib/lib/Model/Surfaces.ts
+++ b/shared-lib/lib/Model/Surfaces.ts
@@ -8,6 +8,11 @@ import type {
} from '@companion-module/base'
import { CompanionInputFieldTextInputExtended, EncodeIsVisible2 } from './Options.js'
+export interface RowsAndColumns {
+ rows: number
+ columns: number
+}
+
export interface ClientSurfaceItem {
id: string
type: string
@@ -17,6 +22,9 @@ export interface ClientSurfaceItem {
isConnected: boolean
displayName: string
location: string | null
+
+ size: RowsAndColumns | null
+ offset: RowsAndColumns | null
}
export interface ClientDevicesListItem {
diff --git a/webui/src/Buttons/ButtonGridPanel.tsx b/webui/src/Buttons/ButtonGridPanel.tsx
index 6739458f46..29d103371c 100644
--- a/webui/src/Buttons/ButtonGridPanel.tsx
+++ b/webui/src/Buttons/ButtonGridPanel.tsx
@@ -26,6 +26,7 @@ import { observer } from 'mobx-react-lite'
import { ButtonGridZoomControl } from './ButtonGridZoomControl.js'
import { GridZoomController } from './GridZoom.js'
import { CModalExt } from '../Components/CModalExt.js'
+import { ButtonGridResizePrompt } from './ButtonGridResizePrompt.js'
interface ButtonsGridPanelProps {
pageNumber: number
@@ -162,6 +163,8 @@ export const ButtonsGridPanel = observer(function ButtonsPage({
and what they should do when you press or click on them.
+
+
diff --git a/webui/src/Buttons/ButtonGridResizePrompt.tsx b/webui/src/Buttons/ButtonGridResizePrompt.tsx
new file mode 100644
index 0000000000..d8e60a6192
--- /dev/null
+++ b/webui/src/Buttons/ButtonGridResizePrompt.tsx
@@ -0,0 +1,35 @@
+import { CAlert, CButton } from '@coreui/react'
+import { observer } from 'mobx-react-lite'
+import React, { useContext } from 'react'
+import { RootAppStoreContext } from '../Stores/RootAppStore.js'
+import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'
+import { faExpand } from '@fortawesome/free-solid-svg-icons'
+
+export const ButtonGridResizePrompt = observer(function ButtonGridResizePrompt(): React.ReactNode {
+ const { socket, surfaces, userConfig } = useContext(RootAppStoreContext)
+
+ const overflowing = userConfig.properties && surfaces.getSurfacesOverflowingBounds(userConfig.properties.gridSize)
+ if (!overflowing || overflowing.surfaces.length === 0) return null
+
+ const doAutoResize = () => {
+ if (!overflowing) return
+ socket.emit('set_userconfig_key', 'gridSize', overflowing.neededBounds)
+ }
+
+ return (
+ <>
+
+ You have some surfaces which overflow the current grid bounds
+
+ {overflowing.surfaces.map((s) => (
+ - {s.displayName}
+ ))}
+
+
+
+ Resize grid to fit
+
+
+ >
+ )
+})
diff --git a/webui/src/Stores/SurfacesStore.tsx b/webui/src/Stores/SurfacesStore.tsx
index 77d8d85577..3e10d45972 100644
--- a/webui/src/Stores/SurfacesStore.tsx
+++ b/webui/src/Stores/SurfacesStore.tsx
@@ -3,11 +3,13 @@ import type {
OutboundSurfaceInfo,
SurfacesUpdate,
OutboundSurfacesUpdate,
+ ClientSurfaceItem,
} from '@companion-app/shared/Model/Surfaces.js'
import { action, observable, toJS } from 'mobx'
import { assertNever } from '../util.js'
import { applyPatch } from 'fast-json-patch'
import { cloneDeep } from 'lodash-es'
+import { UserConfigGridSize } from '@companion-app/shared/Model/UserConfigModel.js'
export class SurfacesStore {
readonly store = observable.map()
@@ -79,12 +81,42 @@ export class SurfacesStore {
public getOutboundStreamDeckSurface = (address: string, port: number): OutboundSurfaceInfo | undefined => {
for (const surface of this.outboundSurfaces.values()) {
- console.log('check', toJS(surface))
-
if (surface.type === 'elgato' && surface.address === address && (surface.port ?? 5343) === port) {
return surface
}
}
return undefined
}
+
+ public getSurfacesOverflowingBounds = (
+ bounds: UserConfigGridSize
+ ): { neededBounds: UserConfigGridSize; surfaces: ClientSurfaceItem[] } => {
+ const neededBounds: UserConfigGridSize = { ...bounds }
+ const overflowingSurfaces: ClientSurfaceItem[] = []
+
+ for (const group of this.store.values()) {
+ for (const surface of group.surfaces) {
+ if (!surface.size || !surface.offset) continue
+
+ const minX = surface.offset.columns
+ const minY = surface.offset.rows
+ const maxX = minX + surface.size.columns - 1
+ const maxY = minY + surface.size.rows - 1
+
+ if (minX < bounds.minColumn || minY < bounds.minRow || maxX > bounds.maxColumn || maxY > bounds.maxRow) {
+ overflowingSurfaces.push(surface)
+
+ neededBounds.minColumn = Math.min(neededBounds.minColumn, minX)
+ neededBounds.maxColumn = Math.max(neededBounds.maxColumn, maxX)
+ neededBounds.minRow = Math.min(neededBounds.minRow, minY)
+ neededBounds.maxRow = Math.max(neededBounds.maxRow, maxY)
+ }
+ }
+ }
+
+ return {
+ neededBounds,
+ surfaces: overflowingSurfaces,
+ }
+ }
}