Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: view as surface #2945

Draft
wants to merge 23 commits into
base: develop
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
23 commits
Select commit Hold shift + click to select a range
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
20 changes: 10 additions & 10 deletions .github/workflows/nodejs.yml
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ jobs:
cd webui
yarn check-types

linux64:
linux-x64:
runs-on: ubuntu-20.04
needs: check-types
timeout-minutes: 20
Expand Down Expand Up @@ -69,7 +69,7 @@ jobs:
yarn --immutable
yarn update

yarn zx tools/build/complete.mjs
yarn zx tools/build/complete.mjs linux-x64

# manually tar it, to preserve the symlinks
cd electron-output
Expand Down Expand Up @@ -180,7 +180,7 @@ jobs:
api-target: 'linux-arm64-tgz'
api-secret: ${{ secrets.BITFOCUS_API_PROJECT_SECRET }}

osx:
osx-x64:
runs-on: macos-12
needs: check-types
timeout-minutes: 60
Expand Down Expand Up @@ -210,7 +210,7 @@ jobs:
yarn --immutable
yarn update

yarn zx tools/build/complete.mjs
yarn zx tools/build/complete.mjs darwin-x64
env:
CI: 1
CSC_LINK: ${{ secrets.OSX_CSC_LINK }}
Expand Down Expand Up @@ -322,7 +322,7 @@ jobs:
api-target: 'mac-arm'
api-secret: ${{ secrets.BITFOCUS_API_PROJECT_SECRET }}

win64:
win32-x64:
runs-on: windows-2019
needs: check-types
timeout-minutes: 30
Expand Down Expand Up @@ -353,7 +353,7 @@ jobs:
yarn --immutable
yarn update

yarn zx tools/build/complete.mjs
yarn zx tools/build/complete.mjs win32-x64
env:
CI: 1
CSC_LINK: ${{ secrets.CSC_LINK }}
Expand Down Expand Up @@ -393,22 +393,22 @@ jobs:
timeout-minutes: 10

needs:
- linux64
- linux-x64
- linux-arm64

env:
IMAGE_NAME: companion

steps:
- name: Docker meta
if: ${{ needs.linux64.outputs.do-docker }}
if: ${{ needs.linux-x64.outputs.do-docker }}
id: meta
uses: docker/metadata-action@v5
with:
images: |
ghcr.io/${{ github.repository }}/${{ env.IMAGE_NAME }}
tags: |
type=raw,value=${{ needs.linux64.outputs.version }}
type=raw,value=${{ needs.linux-x64.outputs.version }}
type=ref,event=tag
type=ref,event=branch

Expand Down Expand Up @@ -444,4 +444,4 @@ jobs:
labels: ${{ steps.meta.outputs.labels }}
tags: '${{ steps.meta.outputs.tags }}'
build-args: |
build_name=${{ needs.linux64.outputs.version }}
build_name=${{ needs.linux-x64.outputs.version }}
44 changes: 43 additions & 1 deletion companion/lib/Surface/Controller.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
// @ts-check
/*
* This file is part of the Companion project
* Copyright (c) 2018 Bitfocus AS
Expand Down Expand Up @@ -41,6 +40,7 @@ import SurfaceIPVideohubPanel from './IP/VideohubPanel.js'
import FrameworkMacropadDriver from './USB/FrameworkMacropad.js'
import CoreBase from '../Core/Base.js'
import { SurfaceGroup } from './Group.js'
import { SurfaceLayoutRegistry } from './LayoutRegistry.js'

// Force it to load the hidraw driver just in case
HID.setDriverType('hidraw')
Expand All @@ -49,6 +49,13 @@ HID.devices()
const SurfacesRoom = 'surfaces'

class SurfaceController extends CoreBase {
/**
* @type {SurfaceLayoutRegistry}
* @access private
* @readonly
*/
#surfaceLayouts

/**
* The last sent json object
* @type {Record<string, ClientDevicesListItem> }
Expand Down Expand Up @@ -112,6 +119,8 @@ class SurfaceController extends CoreBase {
constructor(registry) {
super(registry, 'Surface/Controller')

this.#surfaceLayouts = new SurfaceLayoutRegistry()

this.#surfacesAllLocked = !!this.userconfig.getKey('link_lockouts')

setImmediate(() => {
Expand Down Expand Up @@ -422,6 +431,11 @@ class SurfaceController extends CoreBase {
for (let surface of this.#surfaceHandlers.values()) {
if (surface && surface.surfaceId == id) {
surface.setPanelConfig(config)

setImmediate(() => {
this.updateDevicesList()
})

return surface.getPanelConfig()
}
}
Expand Down Expand Up @@ -531,6 +545,10 @@ class SurfaceController extends CoreBase {

return group.groupConfig
})

client.onPromise('surfaces:get-layouts', () => {
return this.#surfaceLayouts.getLayouts()
})
}

/**
Expand Down Expand Up @@ -651,6 +669,21 @@ class SurfaceController extends CoreBase {
isConnected: !!surfaceHandler,
displayName: getSurfaceName(config, id),
location: null,
xOffset: config.config?.xOffset ?? 0,
yOffset: config.config?.yOffset ?? 0,
layout: config.layout ?? null,
}

// If the surface has a cached grid size, a crude layout can be generated
if (config.gridSize && !surfaceInfo.layout) {
surfaceInfo.layout = {
id: '__auto__',
name: surfaceInfo.displayName,

type: 'grid',
rows: config.gridSize.rows,
columns: config.gridSize.columns,
}
}

if (surfaceHandler) {
Expand All @@ -659,6 +692,15 @@ class SurfaceController extends CoreBase {

surfaceInfo.location = location || null
surfaceInfo.configFields = surfaceHandler.panel.info.configFields || []

surfaceInfo.layout = {
id: '__auto__',
name: surfaceInfo.displayName,

type: 'grid',
rows: surfaceHandler.panelGridSize.rows,
columns: surfaceHandler.panelGridSize.columns,
}
}

return surfaceInfo
Expand Down
194 changes: 194 additions & 0 deletions companion/lib/Surface/LayoutRegistry.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,194 @@
/*
* This file is part of the Companion project
* Copyright (c) 2018 Bitfocus AS
* Authors: William Viker <[email protected]>, Håkon Nessjøen <[email protected]>
*
* This program is free software.
* You should have received a copy of the MIT licence as well as the Bitfocus
* Individual Contributor License Agreement for companion along with
* this program.
*
* You can be released from the requirements of the license by purchasing
* a commercial license. Buying such a license is mandatory as soon as you
* develop commercial activities involving the Companion software without
* disclosing the source code of your own applications.
*
*/

import { PRODUCTS as XKeysProducts } from 'xkeys'
import { contourShuttleXpressInfo, contourShuttleProV1Info, contourShuttleProV2Info } from './USB/ContourShuttle.js'

export class SurfaceLayoutRegistry {
/**
* The list of known surface layouts
* @type {import("@companion-app/shared/Model/Surfaces.js").SurfaceLayoutSchema[]}
* @access private
* @readonly
*/
#layouts = []

constructor() {
this.#addCountourShuttleLayouts()
this.#addStreamdeckLayouts()
this.#addLoupedeckLayouts()
this.#addInfinittonLayouts()
this.#addVideohubLayouts()
this.#addXKeysLayouts()

// Sort by name
this.#layouts.sort((a, b) => a.name.localeCompare(b.name))
}

#addCountourShuttleLayouts() {
this.#layouts.push(
{
id: 'contour-shuttle-xpress',
name: 'Contour Shuttle Xpress',
type: 'grid',
rows: contourShuttleXpressInfo.totalRows,
columns: contourShuttleXpressInfo.totalCols,
},
{
id: 'contour-shuttle-pro-v1',
name: 'Contour Shuttle Pro v1',
type: 'grid',
rows: contourShuttleProV1Info.totalRows,
columns: contourShuttleProV1Info.totalCols,
},
{
id: 'contour-shuttle-pro-v2',
name: 'Contour Shuttle Pro v2',
type: 'grid',
rows: contourShuttleProV2Info.totalRows,
columns: contourShuttleProV2Info.totalCols,
}
)
}

#addStreamdeckLayouts() {
this.#layouts.push(
{
id: 'streamdeck-15',
name: 'Elgato Streamdeck Original',
type: 'grid',
rows: 3,
columns: 5,
},
{
id: 'streamdeck-xl',
name: 'Elgato Streamdeck XL',
type: 'grid',
rows: 4,
columns: 8,
},
{
id: 'streamdeck-mini',
name: 'Elgato Streamdeck Mini',
type: 'grid',
rows: 2,
columns: 3,
},
{
id: 'streamdeck-plus',
name: 'Elgato Streamdeck +',
type: 'grid',
rows: 4,
columns: 4,
},
{
id: 'streamdeck-pedal',
name: 'Elgato Streamdeck Pedal',
type: 'grid',
rows: 1,
columns: 3,
},
{
id: 'streamdeck-neo',
name: 'Elgato Streamdeck Neo',
type: 'grid',
rows: 3,
columns: 4,
}
)
}

#addLoupedeckLayouts() {
this.#layouts.push(
{
id: 'loupedeck-live',
name: 'Loupedeck Live',
type: 'grid',
rows: 4,
columns: 8,
},
{
id: 'loupedeck-live-s',
name: 'Loupedeck Live S',
type: 'grid',
rows: 3,
columns: 7,
},
{
id: 'razer-stream-controller',
name: 'Razer Stream Controller',
type: 'grid',
rows: 4,
columns: 8,
},
{
id: 'razer-stream-controller-x',
name: 'Razer Stream Controller X',
type: 'grid',
rows: 3,
columns: 5,
},
{
id: 'loupedeck-ct',
name: 'Loupedeck CT',
type: 'grid',
rows: 8, // TODO verify
columns: 8,
}
)
}

#addInfinittonLayouts() {
this.#layouts.push({
id: 'infinitton-idisplay',
name: 'Infinitton idisplay',
type: 'grid',
rows: 3,
columns: 5,
})
}

#addVideohubLayouts() {
this.#layouts.push({
id: 'blackmagic-videohub-smart-control',
name: 'Videohub Smart Control',
type: 'grid',
rows: 2,
columns: 20,
})
}

#addXKeysLayouts() {
for (const [id, product] of Object.entries(XKeysProducts)) {
this.#layouts.push({
id: `xkeys-${id}`,
name: `XKeys ${product.name}`,
type: 'grid',

rows: product.rowCount,
columns: product.colCount,
})
}
}

/**
* @returns {import("@companion-app/shared/Model/Surfaces.js").SurfaceLayoutSchema[]}
*/
getLayouts() {
return this.#layouts
}
}
Loading