mirror of
https://github.com/mifi/lossless-cut.git
synced 2024-11-23 02:42:37 +01:00
Implement more consistent segment colors #625
This commit is contained in:
parent
87df1c5e5f
commit
69a3b91926
58
src/App.jsx
58
src/App.jsx
@ -64,7 +64,7 @@ import { adjustRate } from './util/rate-calculator';
|
||||
import { askForOutDir, askForImportChapters, createNumSegments, createFixedDurationSegments, promptTimeOffset, askForHtml5ifySpeed, askForFileOpenAction, confirmExtractAllStreamsDialog, cleanupFilesDialog, showDiskFull, showCutFailedDialog, labelSegmentDialog, openYouTubeChaptersDialog, showMultipleFilesDialog, showOpenAndMergeDialog, openAbout, showEditableJsonDialog } from './dialogs';
|
||||
import { openSendReportDialog } from './reporting';
|
||||
import { fallbackLng } from './i18n';
|
||||
import { createSegment, createInitialCutSegments, getCleanCutSegments, getSegApparentStart, findSegmentsAtCursor, sortSegments, invertSegments, getSegmentTags } from './segments';
|
||||
import { createSegment, getCleanCutSegments, getSegApparentStart, findSegmentsAtCursor, sortSegments, invertSegments, getSegmentTags } from './segments';
|
||||
|
||||
import loadingLottie from './7077-magic-flow.json';
|
||||
|
||||
@ -149,6 +149,19 @@ const App = memo(() => {
|
||||
const [batchFiles, setBatchFiles] = useState([]);
|
||||
|
||||
// Segment related state
|
||||
const segCounterRef = useRef(0);
|
||||
const clearSegCounter = useCallback(() => {
|
||||
segCounterRef.current = 0;
|
||||
}, []);
|
||||
|
||||
const createSegmentAndIncrementCount = useCallback((segment) => {
|
||||
const ret = createSegment({ segIndex: segCounterRef.current, ...segment });
|
||||
segCounterRef.current += 1;
|
||||
return ret;
|
||||
}, []);
|
||||
|
||||
const createInitialCutSegments = useCallback(() => () => [createSegmentAndIncrementCount()], [createSegmentAndIncrementCount]);
|
||||
|
||||
const [currentSegIndex, setCurrentSegIndex] = useState(0);
|
||||
const [cutStartTimeManual, setCutStartTimeManual] = useState();
|
||||
const [cutEndTimeManual, setCutEndTimeManual] = useState();
|
||||
@ -157,6 +170,11 @@ const App = memo(() => {
|
||||
100,
|
||||
);
|
||||
|
||||
const clearSegments = useCallback(() => {
|
||||
clearSegCounter();
|
||||
setCutSegments(createInitialCutSegments());
|
||||
}, [clearSegCounter, createInitialCutSegments, setCutSegments]);
|
||||
|
||||
// Store "working" in a ref so we can avoid race conditions
|
||||
const workingRef = useRef(working);
|
||||
const setWorking = useCallback((val) => {
|
||||
@ -349,7 +367,8 @@ const App = memo(() => {
|
||||
}, [duration, haveInvalidSegs, sortedCutSegments]);
|
||||
|
||||
const invertAllCutSegments = useCallback(() => {
|
||||
const newInverseCutSegments = inverseCutSegments.map(createSegment);
|
||||
// don't reset segIndex (which represent colors) when inverting
|
||||
const newInverseCutSegments = inverseCutSegments.map((inverseSegment, segIndex) => createSegment({ ...inverseSegment, segIndex }));
|
||||
if (newInverseCutSegments.length < 1) {
|
||||
errorToast(i18n.t('Make sure you have no overlapping segments.'));
|
||||
return;
|
||||
@ -456,7 +475,7 @@ const App = memo(() => {
|
||||
|
||||
const cutSegmentsNew = [
|
||||
...cutSegments,
|
||||
createSegment({ start: suggestedStart }),
|
||||
createSegmentAndIncrementCount({ start: suggestedStart }),
|
||||
];
|
||||
|
||||
setCutSegments(cutSegmentsNew);
|
||||
@ -464,9 +483,7 @@ const App = memo(() => {
|
||||
} catch (err) {
|
||||
console.error(err);
|
||||
}
|
||||
}, [
|
||||
currentCutSeg.start, currentCutSeg.end, cutSegments, setCutSegments,
|
||||
]);
|
||||
}, [currentCutSeg.start, currentCutSeg.end, cutSegments, createSegmentAndIncrementCount, setCutSegments]);
|
||||
|
||||
const setCutStart = useCallback(() => {
|
||||
if (!filePath) return;
|
||||
@ -545,8 +562,8 @@ const App = memo(() => {
|
||||
const { cutSegments: saveOperationCutSegments, edlFilePath: saveOperationEdlFilePath, filePath: saveOperationFilePath } = debouncedSaveOperation;
|
||||
|
||||
try {
|
||||
// Initial state? Don't save
|
||||
if (isEqual(getCleanCutSegments(saveOperationCutSegments), getCleanCutSegments(createInitialCutSegments()))) return;
|
||||
// Initial state? Don't save (same as createInitialCutSegments but without counting)
|
||||
if (isEqual(getCleanCutSegments(saveOperationCutSegments), getCleanCutSegments([createSegment()]))) return;
|
||||
|
||||
if (lastSaveOperation.current && lastSaveOperation.current.edlFilePath === saveOperationEdlFilePath && isEqual(getCleanCutSegments(lastSaveOperation.current.cutSegments), getCleanCutSegments(saveOperationCutSegments))) {
|
||||
console.log('Segments unchanged, skipping save');
|
||||
@ -743,7 +760,7 @@ const App = memo(() => {
|
||||
if (cutSegments.length === 1 && cutSegments[0].start == null && cutSegments[0].end == null) return; // Initial segment
|
||||
|
||||
if (cutSegments.length <= 1) {
|
||||
setCutSegments(createInitialCutSegments());
|
||||
clearSegments();
|
||||
return;
|
||||
}
|
||||
|
||||
@ -751,11 +768,7 @@ const App = memo(() => {
|
||||
cutSegmentsNew.splice(index, 1);
|
||||
|
||||
setCutSegments(cutSegmentsNew);
|
||||
}, [cutSegments, setCutSegments]);
|
||||
|
||||
const clearSegments = useCallback(() => {
|
||||
setCutSegments(createInitialCutSegments());
|
||||
}, [setCutSegments]);
|
||||
}, [clearSegments, cutSegments, setCutSegments]);
|
||||
|
||||
const thumnailsRef = useRef([]);
|
||||
const thumnailsRenderingPromiseRef = useRef();
|
||||
@ -823,7 +836,7 @@ const App = memo(() => {
|
||||
setPlaying(false);
|
||||
setDuration();
|
||||
cutSegmentsHistory.go(0);
|
||||
setCutSegments(createInitialCutSegments()); // TODO this will cause two history items
|
||||
clearSegments(); // TODO this will cause two history items
|
||||
setCutStartTimeManual();
|
||||
setCutEndTimeManual();
|
||||
setFileFormat();
|
||||
@ -855,7 +868,7 @@ const App = memo(() => {
|
||||
|
||||
cancelRenderThumbnails();
|
||||
});
|
||||
}, [cutSegmentsHistory, setCutSegments, cancelRenderThumbnails]);
|
||||
}, [cutSegmentsHistory, clearSegments, cancelRenderThumbnails]);
|
||||
|
||||
|
||||
const showUnsupportedFileMessage = useCallback(() => {
|
||||
@ -1247,13 +1260,13 @@ const App = memo(() => {
|
||||
|
||||
const getNewName = (oldName, suffix) => oldName && `${segmentAtCursor2.name} ${suffix}`;
|
||||
|
||||
const firstPart = createSegment({ name: getNewName(segmentAtCursor2.name, '1'), start: segmentAtCursor2.start, end: currentTimeRef.current });
|
||||
const secondPart = createSegment({ name: getNewName(segmentAtCursor2.name, '2'), start: currentTimeRef.current, end: segmentAtCursor2.end });
|
||||
const firstPart = createSegmentAndIncrementCount({ name: getNewName(segmentAtCursor2.name, '1'), start: segmentAtCursor2.start, end: currentTimeRef.current });
|
||||
const secondPart = createSegmentAndIncrementCount({ name: getNewName(segmentAtCursor2.name, '2'), start: currentTimeRef.current, end: segmentAtCursor2.end });
|
||||
|
||||
const newSegments = [...cutSegments];
|
||||
newSegments.splice(firstSegmentAtCursorIndex, 1, firstPart, secondPart);
|
||||
setCutSegments(newSegments);
|
||||
}, [cutSegments, firstSegmentAtCursorIndex, setCutSegments]);
|
||||
}, [createSegmentAndIncrementCount, cutSegments, firstSegmentAtCursorIndex, setCutSegments]);
|
||||
|
||||
const loadCutSegments = useCallback((edl) => {
|
||||
const validEdl = edl.filter((row) => (
|
||||
@ -1266,8 +1279,9 @@ const App = memo(() => {
|
||||
|
||||
if (validEdl.length === 0) throw new Error(i18n.t('No valid segments found'));
|
||||
|
||||
setCutSegments(validEdl.map(createSegment));
|
||||
}, [setCutSegments]);
|
||||
clearSegCounter();
|
||||
setCutSegments(validEdl.map(createSegmentAndIncrementCount));
|
||||
}, [clearSegCounter, createSegmentAndIncrementCount, setCutSegments]);
|
||||
|
||||
const loadEdlFile = useCallback(async (path, type) => {
|
||||
console.log('Loading EDL file', type, path);
|
||||
@ -1979,7 +1993,7 @@ const App = memo(() => {
|
||||
mergeFiles, outputDir, filePath, customOutDir, startTimeOffset, userHtml5ifyCurrentFile,
|
||||
extractAllStreams, userOpenFiles, openSendReportDialogWithState, setWorking,
|
||||
loadEdlFile, cutSegments, apparentCutSegments, edlFilePath, toggleHelp, toggleSettings, ensureOutDirAccessible, html5ifyAndLoad, html5ify,
|
||||
loadCutSegments, duration, checkFileOpened, loadMedia, fileFormat, reorderSegsByStartTime, closeFileWithConfirm, closeBatch, clearSegments, fixInvalidDuration, invertAllCutSegments, getFrameCount,
|
||||
loadCutSegments, duration, checkFileOpened, loadMedia, fileFormat, reorderSegsByStartTime, closeFileWithConfirm, closeBatch, clearSegments, clearSegCounter, fixInvalidDuration, invertAllCutSegments, getFrameCount,
|
||||
]);
|
||||
|
||||
const showAddStreamSourceDialog = useCallback(async () => {
|
||||
|
@ -1,14 +1,12 @@
|
||||
import { v4 as uuidv4 } from 'uuid';
|
||||
import sortBy from 'lodash/sortBy';
|
||||
|
||||
import { generateColor } from './util/colors';
|
||||
|
||||
export const createSegment = ({ start, end, name, tags } = {}) => ({
|
||||
export const createSegment = ({ start, end, name, tags, segIndex } = {}) => ({
|
||||
start,
|
||||
end,
|
||||
name: name || '',
|
||||
color: generateColor(),
|
||||
segId: uuidv4(),
|
||||
segIndex,
|
||||
|
||||
// `tags` is an optional object (key-value). Values must always be string
|
||||
// See https://github.com/mifi/lossless-cut/issues/879
|
||||
@ -17,8 +15,6 @@ export const createSegment = ({ start, end, name, tags } = {}) => ({
|
||||
: undefined,
|
||||
});
|
||||
|
||||
export const createInitialCutSegments = () => [createSegment()];
|
||||
|
||||
// Because segments could have undefined start / end
|
||||
// (meaning extend to start of timeline or end duration)
|
||||
export function getSegApparentStart(seg) {
|
||||
|
@ -1,15 +1,31 @@
|
||||
import randomColor from './random-color';
|
||||
import color from 'color';
|
||||
|
||||
export function generateColor() {
|
||||
return randomColor(1, 0.95);
|
||||
}
|
||||
// https://github.com/mock-end/random-color/blob/master/index.js
|
||||
/* eslint-disable */
|
||||
function getColor(saturation, value, n) {
|
||||
var ratioMul = 0.618033988749895;
|
||||
var initialHue = 0.65;
|
||||
|
||||
const hue = (initialHue + ((n + 1) * ratioMul)) % 1;
|
||||
|
||||
return color({
|
||||
h: hue * 360,
|
||||
s: saturation * 100,
|
||||
v: value * 100,
|
||||
});
|
||||
};
|
||||
/* eslint-enable */
|
||||
|
||||
// eslint-disable-next-line import/prefer-default-export
|
||||
export function getSegColors(seg) {
|
||||
if (!seg) return {};
|
||||
const { color } = seg;
|
||||
const { segIndex } = seg;
|
||||
|
||||
const segColor = getColor(1, 0.95, segIndex);
|
||||
|
||||
return {
|
||||
segBgColor: color.alpha(0.5).string(),
|
||||
segActiveBgColor: color.lighten(0.5).alpha(0.5).string(),
|
||||
segBorderColor: color.lighten(0.5).string(),
|
||||
segBgColor: segColor.alpha(0.5).string(),
|
||||
segActiveBgColor: segColor.lighten(0.5).alpha(0.5).string(),
|
||||
segBorderColor: segColor.lighten(0.5).string(),
|
||||
};
|
||||
}
|
||||
|
@ -1,26 +0,0 @@
|
||||
// https://github.com/mock-end/random-color/blob/master/index.js
|
||||
/* eslint-disable */
|
||||
|
||||
import color from 'color';
|
||||
|
||||
var ratio = 0.618033988749895;
|
||||
var hue = 0.65;
|
||||
|
||||
export default (saturation, value) => {
|
||||
hue += ratio;
|
||||
hue %= 1;
|
||||
|
||||
if (typeof saturation !== 'number') {
|
||||
saturation = 0.5;
|
||||
}
|
||||
|
||||
if (typeof value !== 'number') {
|
||||
value = 0.95;
|
||||
}
|
||||
|
||||
return color({
|
||||
h: hue * 360,
|
||||
s: saturation * 100,
|
||||
v: value * 100,
|
||||
});
|
||||
};
|
Loading…
Reference in New Issue
Block a user