Skip to content

Commit 970f42e

Browse files
committed
Merge branch 'release51'
2 parents 4a7544c + fa6eac6 commit 970f42e

File tree

3 files changed

+126
-20
lines changed

3 files changed

+126
-20
lines changed

meteor/client/styles/shelf/shelf.scss

Lines changed: 36 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -128,33 +128,61 @@
128128
}
129129

130130
.rundown-view__shelf__tabs__tab {
131+
position: relative;
131132
display: block;
132133
background: none;
133134
border: none;
134-
position: relative;
135135
flex: 1 1;
136136
max-width: 7em;
137-
min-width: 13em;
137+
min-width: min-content;
138138
overflow: hidden;
139139
text-overflow: ellipsis;
140140
white-space: nowrap;
141141
text-align: center;
142-
color: #8f8f8f;
143142
line-height: $inspector-shelf-tabs-height;
144143
cursor: pointer;
145144
user-select: none;
145+
padding-inline: 1.5em;
146146

147147
outline-offset: -5px;
148148

149+
// this is a setup that ensures that the min-content is calculated with this font-weight,
150+
// while we display the button with differing font-weights depending on state
151+
font-weight: 500;
152+
color: transparent;
153+
149154
&:hover {
150-
color: #fff;
151-
transition: 0.3s;
155+
// color: #fff;
156+
// transition: 0.3s;
157+
158+
> .rundown-view__shelf__tabs__tab-label {
159+
color: #fff;
160+
transition: 0.3s;
161+
}
162+
}
163+
164+
> .rundown-view__shelf__tabs__tab-label {
165+
position: absolute;
166+
top: 0;
167+
left: 0;
168+
right: 0;
169+
line-height: inherit;
170+
font-weight: 300;
171+
color: #b0b0b0;
152172
}
153173

154174
&.selected {
155-
color: #fff;
156-
font-weight: 500;
157-
text-shadow: 0 0 5px #000;
175+
// color: #fff;
176+
// font-weight: 500;
177+
// text-shadow: 0 0 5px #000;
178+
// transition: 0s;
179+
180+
> .rundown-view__shelf__tabs__tab-label {
181+
color: #fff;
182+
font-weight: 500;
183+
text-shadow: 0 0 5px #000;
184+
transition: 0s;
185+
}
158186

159187
&::after {
160188
content: ' ';

meteor/client/ui/Shelf/ShelfRundownLayout.tsx

Lines changed: 14 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,7 @@ export function ShelfRundownLayout(props: Readonly<IShelfRundownLayoutProps>): J
5252
tabIndex={0}
5353
role="tab"
5454
>
55+
<div className="rundown-view__shelf__tabs__tab-label">{t('AdLib')}</div>
5556
{t('AdLib')}
5657
</button>
5758
<button
@@ -62,6 +63,7 @@ export function ShelfRundownLayout(props: Readonly<IShelfRundownLayoutProps>): J
6263
tabIndex={0}
6364
role="tab"
6465
>
66+
<div className="rundown-view__shelf__tabs__tab-label">{t('Global AdLib')}</div>
6567
{t('Global AdLib')}
6668
</button>
6769
</>
@@ -79,21 +81,23 @@ export function ShelfRundownLayout(props: Readonly<IShelfRundownLayoutProps>): J
7981
tabIndex={0}
8082
role="tab"
8183
>
84+
<div className="rundown-view__shelf__tabs__tab-label">{panel.name}</div>
8285
{panel.name}
8386
</button>
8487
))
8588
)}
89+
<button
90+
className={ClassNames('rundown-view__shelf__tabs__tab', {
91+
selected: (props.selectedTab || SHELF_DEFAULT_TAB) === ShelfTabs.SYSTEM_HOTKEYS,
92+
})}
93+
onClick={() => onSwitchTab(ShelfTabs.SYSTEM_HOTKEYS)}
94+
tabIndex={0}
95+
role="tab"
96+
>
97+
<div className="rundown-view__shelf__tabs__tab-label">{t('Shortcuts')}</div>
98+
{t('Shortcuts')}
99+
</button>
86100
</OverflowingContainer>
87-
<button
88-
className={ClassNames('rundown-view__shelf__tabs__tab', {
89-
selected: (props.selectedTab || SHELF_DEFAULT_TAB) === ShelfTabs.SYSTEM_HOTKEYS,
90-
})}
91-
onClick={() => onSwitchTab(ShelfTabs.SYSTEM_HOTKEYS)}
92-
tabIndex={0}
93-
role="tab"
94-
>
95-
{t('Shortcuts')}
96-
</button>
97101
</div>
98102
<div className="rundown-view__shelf__panel super-dark" role="tabpanel">
99103
{!rundownLayout ? (

packages/job-worker/src/playout/timeline/multi-gateway.ts

Lines changed: 76 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ import { TimelineObjRundown } from '@sofie-automation/corelib/dist/dataModel/Tim
55
import { normalizeArray } from '@sofie-automation/corelib/dist/lib'
66
import { PieceTimelineMetadata } from './pieceGroup'
77
import { StudioPlayoutModelBase } from '../../studio/model/StudioPlayoutModel'
8+
import { logger } from '../../logging'
89
import { JobContext } from '../../jobs'
910
import { getCurrentTime } from '../../lib'
1011
import { PlayoutModel } from '../model/PlayoutModel'
@@ -46,7 +47,7 @@ export function deNowifyMultiGatewayTimeline(
4647
playoutModel.nextPartInstance
4748
)
4849

49-
deNowifyCurrentPieces(
50+
const { objectsNotDeNowified } = deNowifyCurrentPieces(
5051
targetNowTime,
5152
timingContext,
5253
currentPartInstance,
@@ -55,6 +56,9 @@ export function deNowifyMultiGatewayTimeline(
5556
)
5657

5758
updatePlannedTimingsForPieceInstances(playoutModel, currentPartInstance, partGroupTimings, timelineObjsMap)
59+
60+
// Because updatePlannedTimingsForPieceInstances changes start times of infinites, we can now run deNowifyInfinites()
61+
deNowifyInfinites(targetNowTime, objectsNotDeNowified, timelineObjsMap)
5862
}
5963

6064
/**
@@ -142,16 +146,83 @@ function updatePartInstancePlannedTimes(
142146
}
143147
}
144148

149+
/**
150+
* Replace the `now` time in any timeline objects in freshly-placed infinites.
151+
*
152+
* This is effectively only needed when a new item has been placed on the timeline just now and changes made by
153+
* `updatePlannedTimingsForPieceInstances` haven't been taken into account when generating the timeline. On the next
154+
* regeneration, items will already use the timestamps persited by `updatePlannedTimingsForPieceInstances` and will not
155+
* be included in `infiniteObjs`.
156+
*/
157+
function deNowifyInfinites(
158+
targetNowTime: number,
159+
/** A list of objects that need to be updated */
160+
infiniteObjs: TimelineObjRundown[],
161+
timelineObjsMap: Record<string, TimelineObjRundown>
162+
) {
163+
/**
164+
* Recursively look up the absolute starttime of a timeline object
165+
* taking into account its parent's times.
166+
* Note: This only supports timeline objects that have absolute enable.start times.
167+
*/
168+
const getStartTime = (obj: TimelineObjRundown): number | undefined => {
169+
if (Array.isArray(obj.enable)) return undefined
170+
171+
const myStartTime = typeof obj.enable.start === 'number' ? obj.enable.start : undefined
172+
173+
if (!obj.inGroup) return myStartTime
174+
175+
if (myStartTime === undefined) return undefined
176+
177+
const parentObject = timelineObjsMap[obj.inGroup]
178+
if (!parentObject) return undefined
179+
180+
const parentStartTime = getStartTime(parentObject)
181+
if (parentStartTime === undefined) return undefined
182+
183+
return parentStartTime + myStartTime
184+
}
185+
186+
for (const obj of infiniteObjs) {
187+
if (Array.isArray(obj.enable) || obj.enable.start !== 'now') continue
188+
189+
if (!obj.inGroup) {
190+
obj.enable = { start: targetNowTime }
191+
continue
192+
}
193+
194+
const parentObject = timelineObjsMap[obj.inGroup]
195+
if (!parentObject) {
196+
logger.error(`deNowifyInfinites: Parent obj "${obj.inGroup}" not found of object "${obj.id}"`)
197+
continue
198+
}
199+
200+
const parentStartTime = getStartTime(parentObject)
201+
if (parentStartTime === undefined) {
202+
logger.error(
203+
`deNowifyInfinites: Unable to derive an absolute start time of parent "${obj.inGroup}" for object "${obj.id}"`
204+
)
205+
continue
206+
}
207+
208+
obj.enable = { start: targetNowTime - parentStartTime }
209+
logger.silly(
210+
`deNowifyInfinites: Setting "${obj.id}" enable.start = ${obj.enable.start}, ${targetNowTime} ${parentStartTime} parentObject: "${parentObject.id}"`
211+
)
212+
}
213+
}
145214
/**
146215
* Replace the `now` time in any Pieces on the timeline from the current Part with concrete start times
216+
* @returns a list of object that couldn't be updated at this time.
147217
*/
148218
function deNowifyCurrentPieces(
149219
targetNowTime: number,
150220
timingContext: RundownTimelineTimingContext,
151221
currentPartInstance: PlayoutPartInstanceModel,
152222
currentPartGroupStartTime: number,
153223
timelineObjsMap: Record<string, TimelineObjRundown>
154-
) {
224+
): { objectsNotDeNowified: TimelineObjRundown[] } {
225+
const objectsNotDeNowified: TimelineObjRundown[] = []
155226
// The relative time for 'now' to be resolved to, inside of the part group
156227
const nowInPart = targetNowTime - currentPartGroupStartTime
157228

@@ -176,6 +247,8 @@ function deNowifyCurrentPieces(
176247
obj.enable = { start: nowInPart }
177248
} else if (!obj.inGroup) {
178249
obj.enable = { start: targetNowTime }
250+
} else {
251+
objectsNotDeNowified.push(obj)
179252
}
180253
}
181254
}
@@ -203,6 +276,7 @@ function deNowifyCurrentPieces(
203276
}
204277
}
205278
}
279+
return { objectsNotDeNowified }
206280
}
207281

208282
function updatePlannedTimingsForPieceInstances(

0 commit comments

Comments
 (0)