Skip to content

Commit

Permalink
Move centerWindowsIfNeeded to an action creatorThis forces us to type…
Browse files Browse the repository at this point in the history
… it, as a nice side benefit
  • Loading branch information
captbaritone committed Oct 1, 2018
1 parent bef421e commit 40e31f0
Show file tree
Hide file tree
Showing 5 changed files with 85 additions and 91 deletions.
3 changes: 2 additions & 1 deletion js/actionCreators/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,8 @@ export {
toggleWindow,
updateWindowPositions,
toggleMainWindowShadeMode,
windowsHaveBeenCentered
windowsHaveBeenCentered,
centerWindowsIfNeeded
} from "./windows";
export {
play,
Expand Down
74 changes: 72 additions & 2 deletions js/actionCreators/windows.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,10 @@
import {
getWindowGraph,
getWindowSizes,
getWindowPositions
getWindowPositions,
getWindowsInfo,
getWindowOpen,
getGenWindows
} from "../selectors";

import { objectMap } from "../utils";
Expand All @@ -20,6 +23,9 @@ import { getPositionDiff, SizeDiff } from "../resizeUtils";
import { applyDiff } from "../snapUtils";
import { Action, Dispatchable, WindowId, WindowPositions } from "../types";

import { WINDOW_HEIGHT, WINDOW_WIDTH } from "../constants";
import { calculateBoundingBox } from "../utils";

// Dispatch an action and, if needed rearrange the windows to preserve
// the existing edge relationship.
//
Expand Down Expand Up @@ -111,6 +117,70 @@ export function updateWindowPositions(
return { type: UPDATE_WINDOW_POSITIONS, positions, center };
}

export function windowsHaveBeenCentered() {
export function windowsHaveBeenCentered(): Dispatchable {
return { type: WINDOWS_HAVE_BEEN_CENTERED };
}

export function centerWindowsIfNeeded(container: HTMLElement): Dispatchable {
return (dispatch, getState) => {
const state = getState();
const { centerRequested } = state.windows;
if (!centerRequested) {
return;
}
const genWindows = getGenWindows(state);
const windowsInfo = getWindowsInfo(state);
const getOpen = getWindowOpen(state);
const rect = container.getBoundingClientRect();

const offsetLeft = rect.left + window.scrollX;
const offsetTop = rect.top + window.scrollY;
const width = container.scrollWidth;
const height = container.scrollHeight;

if (windowsInfo.some(w => w.x == null || w.y == null)) {
// Some windows do not have an initial position, so we'll come up
// with your own layout.
const windowPositions: WindowPositions = {};
const keys: string[] = Object.keys(genWindows).filter(
windowId => genWindows[windowId].open
);
const totalHeight = keys.length * WINDOW_HEIGHT;
const globalOffsetLeft = Math.max(0, width / 2 - WINDOW_WIDTH / 2);
const globalOffsetTop = Math.max(0, height / 2 - totalHeight / 2);
keys.forEach((key, i) => {
const offset = WINDOW_HEIGHT * i;
windowPositions[key] = {
x: Math.ceil(offsetLeft + globalOffsetLeft),
y: Math.ceil(offsetTop + (globalOffsetTop + offset))
};
});
dispatch(updateWindowPositions(windowPositions, false));
} else {
// A layout has been suplied. We will compute the bounding box and
// center the given layout.
const bounding = calculateBoundingBox(
windowsInfo.filter(w => getOpen(w.key))
);

const boxHeight = bounding.bottom - bounding.top;
const boxWidth = bounding.right - bounding.left;

const move = {
x: Math.ceil(offsetLeft - bounding.left + (width - boxWidth) / 2),
y: Math.ceil(offsetTop - bounding.top + (height - boxHeight) / 2)
};

const newPositions = windowsInfo.reduce(
(pos, w) => ({
...pos,
[w.key]: { x: move.x + w.x, y: move.y + w.y }
}),
{}
);

dispatch(updateWindowPositions(newPositions, false));
}
dispatch(windowsHaveBeenCentered());
};
}
86 changes: 8 additions & 78 deletions js/components/WindowManager.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,19 +11,12 @@ import {
applyDiff,
applyMultipleDiffs
} from "../snapUtils";
import {
getWindowsInfo,
getWindowHidden,
getWindowOpen,
getCenterRequested
} from "../selectors";
import { getWindowsInfo, getWindowHidden, getWindowOpen } from "../selectors";
import {
updateWindowPositions,
windowsHaveBeenCentered
windowsHaveBeenCentered,
centerWindowsIfNeeded
} from "../actionCreators";
import { WINDOW_HEIGHT, WINDOW_WIDTH } from "../constants";
import { calculateBoundingBox } from "../utils";

const abuts = (a, b) => {
// TODO: This is kinda a hack. They should really be touching, not just within snapping distance.
// Also, overlapping should not count.
Expand All @@ -33,65 +26,9 @@ const abuts = (a, b) => {

class WindowManager extends React.Component {
componentDidMount() {
this.centerWindowsIfNeeded();
this.props.centerWindowsIfNeeded(this.props.container);
}

centerWindowsIfNeeded = () => {
const { container, centerRequested } = this.props;
if (!centerRequested) {
return;
}

const rect = container.getBoundingClientRect();
const offsetLeft = rect.left + window.scrollX;
const offsetTop = rect.top + window.scrollY;
const width = container.scrollWidth;
const height = container.scrollHeight;

if (this.props.windowsInfo.some(w => w.x == null || w.y == null)) {
// Some windows do not have an initial position, so we'll come up
// with your own layout.
const windowPositions = {};
const keys = this.windowKeys();
const totalHeight = keys.length * WINDOW_HEIGHT;
const globalOffsetLeft = Math.max(0, width / 2 - WINDOW_WIDTH / 2);
const globalOffsetTop = Math.max(0, height / 2 - totalHeight / 2);
keys.forEach((key, i) => {
const offset = WINDOW_HEIGHT * i;
windowPositions[key] = {
x: Math.ceil(offsetLeft + globalOffsetLeft),
y: Math.ceil(offsetTop + (globalOffsetTop + offset))
};
});
this.props.updateWindowPositions(windowPositions, false);
} else {
// A layout has been suplied. We will compute the bounding box and
// center the given layout.
const bounding = calculateBoundingBox(
this.props.windowsInfo.filter(w => this.props.getWindowOpen(w.key))
);

const boxHeight = bounding.bottom - bounding.top;
const boxWidth = bounding.right - bounding.left;

const move = {
x: Math.ceil(offsetLeft - bounding.left + (width - boxWidth) / 2),
y: Math.ceil(offsetTop - bounding.top + (height - boxHeight) / 2)
};

const newPositions = this.props.windowsInfo.reduce(
(pos, w) => ({
...pos,
[w.key]: { x: move.x + w.x, y: move.y + w.y }
}),
{}
);

this.props.updateWindowPositions(newPositions, false);
}
this.props.windowsHaveBeenCentered();
};

movingAndStationaryNodes(key) {
const windows = this.props.windowsInfo.filter(
w =>
Expand Down Expand Up @@ -183,14 +120,6 @@ class WindowManager extends React.Component {
window.addEventListener("mousemove", handleMouseMove);
};

// Keys for the visible windows
windowKeys() {
// TODO: Iterables can probably do this better.
return Object.keys(this.props.windows).filter(
key => !!this.props.windows[key]
);
}

render() {
const style = {
position: "absolute",
Expand Down Expand Up @@ -222,15 +151,16 @@ WindowManager.propTypes = {
const mapStateToProps = state => ({
windowsInfo: getWindowsInfo(state),
getWindowHidden: getWindowHidden(state),
getWindowOpen: getWindowOpen(state),
centerRequested: getCenterRequested(state)
getWindowOpen: getWindowOpen(state)
});

const mapDispatchToProps = dispatch => {
return {
updateWindowPositions: (positions, centered) =>
dispatch(updateWindowPositions(positions, centered)),
windowsHaveBeenCentered: () => dispatch(windowsHaveBeenCentered())
windowsHaveBeenCentered: () => dispatch(windowsHaveBeenCentered()),
centerWindowsIfNeeded: container =>
dispatch(centerWindowsIfNeeded(container))
};
};

Expand Down
1 change: 1 addition & 0 deletions js/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -342,6 +342,7 @@ export type Action =
| {
type: "MINIMIZE_WINAMP";
}
| { type: "WINDOWS_HAVE_BEEN_CENTERED" }
| {
type: "CLOSE_REQUESTED";
cancel: () => void;
Expand Down
12 changes: 2 additions & 10 deletions js/utils.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import { DEFAULT_SKIN } from "./constants";
import { WindowInfo } from "./types";

interface Time {
minutesFirstDigit: string;
Expand Down Expand Up @@ -318,16 +319,7 @@ export function objectFilter<V>(
}, {});
}

interface Window {
left: number;
top: number;
x: number;
y: number;
width: number;
height: number;
}

export const calculateBoundingBox = (windows: Window[]) =>
export const calculateBoundingBox = (windows: WindowInfo[]) =>
windows
.map(w => ({
left: w.x,
Expand Down

0 comments on commit 40e31f0

Please sign in to comment.