Skip to content

Commit

Permalink
Don't resize outside timeline boundary (#119)
Browse files Browse the repository at this point in the history
* Don't resize outside timeline boundary

* Stop resize when mouse enters selection panel

* add 500px of empty space to bottom of timeline scroll view

* Consolidate duplicate resize logic

* use Math.min
  • Loading branch information
ALevansSamsung authored Jun 27, 2024
1 parent 3f4f876 commit edf7ccb
Show file tree
Hide file tree
Showing 3 changed files with 96 additions and 86 deletions.
4 changes: 4 additions & 0 deletions ui/src/assets/common.scss
Original file line number Diff line number Diff line change
Expand Up @@ -522,6 +522,10 @@ canvas.main-canvas {
user-select: none;
}

.scrolling-panel-container > .panels > *:last-child {
margin-bottom: 500px;
}

.panel {
position: relative; // Otherwise canvas covers panel dom.

Expand Down
52 changes: 12 additions & 40 deletions ui/src/frontend/track_group_panel.ts
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ import {
} from './icons';
import {Panel, PanelSize} from './panel';
import {Track} from './track';
import {TrackButton, TrackContent} from './track_panel';
import {TrackButton, TrackContent, checkTrackForResizability, resizeTrack} from './track_panel';
import {trackRegistry} from './track_registry';
import {
drawVerticalLineAtTime,
Expand All @@ -47,7 +47,6 @@ interface Attrs {
selectable: boolean;
}

const MOUSE_TARGETING_THRESHOLD_PX = 5;
export class TrackGroupPanel extends Panel<Attrs> {
private readonly trackGroupId: string;
private shellWidth = 0;
Expand Down Expand Up @@ -101,55 +100,28 @@ export class TrackGroupPanel extends Panel<Attrs> {
get summaryTrackState(): TrackState {
return assertExists(globals.state.tracks[this.trackGroupState.tracks[0]]);
}

resize = (e: MouseEvent): void => {
e.stopPropagation();
e.preventDefault();
if (!this.summaryTrack) {
if (!this.summaryTrack || !this.defaultHeight) {
return;
}
let y = this.summaryTrack.getHeight();
const mouseMoveEvent = (evMove: MouseEvent): void => {
evMove.preventDefault();
y += evMove.movementY;
if (this.attrs && this.defaultHeight) {
const newMultiplier = y / this.defaultHeight;
if (newMultiplier < 1) {
this.summaryTrackState.scaleFactor = 1;
} else {
this.summaryTrackState.scaleFactor = newMultiplier;
}
globals.rafScheduler.scheduleFullRedraw();
}
};
const mouseUpEvent = (): void => {
document.removeEventListener('mousemove', mouseMoveEvent);
document.removeEventListener('mouseup', mouseUpEvent);
};
document.addEventListener('mousemove', mouseMoveEvent);
document.addEventListener('mouseup', mouseUpEvent);
document.removeEventListener('mousedown', this.resize);
resizeTrack(
e,
this.summaryTrack,
this.summaryTrackState,
this.defaultHeight);
};

onmousemove(e: MouseEvent) {
if (this.summaryTrack && this.summaryTrack.supportsResizing) {
if (e.currentTarget instanceof HTMLElement &&
e.pageY - e.currentTarget.getBoundingClientRect().top >=
e.currentTarget.clientHeight - MOUSE_TARGETING_THRESHOLD_PX
) {
document.addEventListener('mousedown', this.resize);
e.currentTarget.style.cursor = 'row-resize';
return;
} else if (e.currentTarget instanceof HTMLElement) {
e.currentTarget.style.cursor = 'unset';
}
if (this.summaryTrack) {
checkTrackForResizability(e, this.summaryTrack, this.resize);
}
document.removeEventListener('mousedown', this.resize);
}
onmouseleave(e: MouseEvent) {
if (this.summaryTrack && this.summaryTrack.supportsResizing &&
e.currentTarget instanceof HTMLElement) {
e.currentTarget.style.cursor = 'unset';
document.removeEventListener('mousedown', this.resize);
if (this.summaryTrack) {
checkTrackForResizability(e, this.summaryTrack, this.resize);
}
}

Expand Down
126 changes: 80 additions & 46 deletions ui/src/frontend/track_panel.ts
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,73 @@ function isSelected(id: string) {
return selectedArea.tracks.includes(id);
}

const RESIZING_HEIGHT_PX = 5;
export function checkTrackForResizability(
e: MouseEvent,
track: Track,
resize: (e: MouseEvent) => void): void {
if (track.supportsResizing) {
if (e.currentTarget instanceof HTMLElement &&
e.type !== 'mouseleave' &&
e.pageY - e.currentTarget.getBoundingClientRect().top >=
e.currentTarget.clientHeight - RESIZING_HEIGHT_PX
) {
const timelineElement: HTMLDivElement | null = e.currentTarget.closest('div.pan-and-zoom-content');
timelineElement?.addEventListener('mousedown', resize);
e.currentTarget.style.cursor = 'row-resize';
return;
} else if (e.currentTarget instanceof HTMLElement) {
const timelineElement: HTMLDivElement | null = e.currentTarget.closest('div.pan-and-zoom-content');
timelineElement?.removeEventListener('mousedown', resize);
e.currentTarget.style.cursor = 'unset';
}
}
}
export function resizeTrack(
e: MouseEvent,
track: Track,
trackState: TrackState,
defaultHeight: number,
pinnedCopy?: boolean ): void {
if (e.currentTarget instanceof HTMLElement) {
const timelineElement = e.currentTarget.closest('div.pan-and-zoom-content');
if (timelineElement && timelineElement instanceof HTMLDivElement) {
let trackHeight = track.getHeight();
let mouseY = e.clientY;
const mouseMoveEvent = (evMove: MouseEvent): void => {
evMove.preventDefault();
let movementY = evMove.clientY-mouseY;
if (pinnedCopy !== true &&
isPinned(trackState.id)) {
movementY /=2;
}
trackHeight += movementY;
mouseY = evMove.clientY;
const newMultiplier = trackHeight / defaultHeight;
trackState.scaleFactor = Math.min(1, newMultiplier);
globals.rafScheduler.scheduleFullRedraw();
};
const mouseReturnEvent = () : void => {
timelineElement.addEventListener('mousemove', mouseMoveEvent);
timelineElement.removeEventListener('mouseenter', mouseReturnEvent);
};
const mouseLeaveEvent = () : void => {
timelineElement.removeEventListener('mousemove', mouseMoveEvent);
timelineElement.addEventListener('mouseenter', mouseReturnEvent);
};
const mouseUpEvent = (): void => {
timelineElement.removeEventListener('mousemove', mouseMoveEvent);
document.removeEventListener('mouseup', mouseUpEvent);
timelineElement.removeEventListener('mouseenter', mouseReturnEvent);
timelineElement.removeEventListener('mouseleave', mouseLeaveEvent);
};
timelineElement.addEventListener('mousemove', mouseMoveEvent);
timelineElement.addEventListener('mouseleave', mouseLeaveEvent);
document.addEventListener('mouseup', mouseUpEvent);
}
}
};

interface TrackShellAttrs {
track: Track;
trackState: TrackState;
Expand Down Expand Up @@ -185,62 +252,29 @@ class TrackShell implements m.ClassComponent<TrackShellAttrs> {
}) :
''));
}

resize = (e: MouseEvent): void => {
e.stopPropagation();
e.preventDefault();
if (!this.attrs) {
if (!this.attrs || !this.defaultHeight) {
return;
}
let y = this.attrs.track.getHeight();
const mouseMoveEvent = (evMove: MouseEvent): void => {
if (!this.attrs) {
return;
}
evMove.preventDefault();
let movementY = evMove.movementY;
if (this.attrs.pinnedCopy !== true &&
isPinned(this.attrs.trackState.id)) {
movementY /=2;
}
y += movementY;
if (this.defaultHeight) {
const newMultiplier = y / this.defaultHeight;
if (newMultiplier < 1) {
this.attrs.trackState.scaleFactor = 1;
} else {
this.attrs.trackState.scaleFactor = newMultiplier;
}
globals.rafScheduler.scheduleFullRedraw();
}
};
const mouseUpEvent = (): void => {
document.removeEventListener('mousemove', mouseMoveEvent);
document.removeEventListener('mouseup', mouseUpEvent);
};
document.addEventListener('mousemove', mouseMoveEvent);
document.addEventListener('mouseup', mouseUpEvent);
document.removeEventListener('mousedown', this.resize);
};
resizeTrack(
e,
this.attrs.track,
this.attrs.trackState,
this.defaultHeight,
this.attrs.pinnedCopy);
};

onmousemove(e: MouseEvent) {
if (this.attrs?.track.supportsResizing) {
if (e.currentTarget instanceof HTMLElement &&
e.pageY - e.currentTarget.getBoundingClientRect().top >=
e.currentTarget.clientHeight - 5) {
document.addEventListener('mousedown', this.resize);
e.currentTarget.style.cursor = 'row-resize';
return;
} else if (e.currentTarget instanceof HTMLElement) {
e.currentTarget.style.cursor = 'unset';
}
if (this.attrs?.track) {
checkTrackForResizability(e, this.attrs.track, this.resize);
}
document.removeEventListener('mousedown', this.resize);
}
onmouseleave(e: MouseEvent) {
if (this.attrs?.track.supportsResizing &&
e.currentTarget instanceof HTMLElement) {
e.currentTarget.style.cursor = 'unset';
document.removeEventListener('mousedown', this.resize);
if (this.attrs?.track) {
checkTrackForResizability(e, this.attrs.track, this.resize);
}
}

Expand Down

0 comments on commit edf7ccb

Please sign in to comment.