More EQ stuff

This commit is contained in:
Jordan Eldredge 2016-08-23 17:28:52 -07:00
parent 8d6357f26c
commit 4fb6467015
9 changed files with 370 additions and 130 deletions

View file

@ -9,6 +9,38 @@
width: 275px;
}
#winamp2-js #on {
position: absolute;
width: 26px;
height: 12px;
top: 18px;
left: 14px;
}
#winamp2-js #auto {
position: absolute;
width: 32px;
height: 12px;
top: 18px;
left: 40px;
}
#winamp2-js #presets {
position: absolute;
width: 44px;
height: 12px;
top: 18px;
left: 217px;
}
#winamp2-js #eqGraph {
position: absolute;
width: 113px;
height: 19px;
top: 17px;
left: 86px;
}
#winamp2-js #preamp {
position: absolute;
left: 20px;

View file

@ -51,4 +51,4 @@ class Band extends React.Component {
}
}
export default connect((state) => state.equalizer)(Band);
export default connect((state) => state.equalizer.sliders)(Band);

27
js/components/EqAuto.jsx Normal file
View file

@ -0,0 +1,27 @@
import React from 'react';
import {connect} from 'react-redux';
import classnames from 'classnames';
class EqAuto extends React.Component {
constructor(props) {
super(props);
this.handleClick = this.handleClick.bind(this);
}
handleClick() {
this.props.dispatch({type: 'TOGGLE_EQ_AUTO'});
}
render() {
const className = classnames({
selected: this.props.auto
});
return <div
id='auto'
className={className}
onClick={this.handleClick}
/>;
}
}
module.exports = connect((state) => state.equalizer)(EqAuto);

88
js/components/EqGraph.jsx Normal file
View file

@ -0,0 +1,88 @@
import React from 'react';
import {connect} from 'react-redux';
export const getY = (value) => (
32 - ((value / 100) * 32)
);
class EqGraph extends React.Component {
constructor(props) {
super(props);
}
componentDidMount() {
this.canvasCtx = this.refs.canvas.getContext('2d');
this.canvasCtx.imageSmoothingEnabled = false;
this.width = this.refs.canvas.width * 1; // Cast to int
this.height = this.refs.canvas.height * 1; // Cast to int
this.bgImage = new Image();
this.bgImage.onload = () => {
this.createColorPattern();
this.componentDidUpdate();
};
this.bgImage.src = 'bg.png';
}
componentDidUpdate() {
this.canvasCtx.clearRect(0, 0, this.width, this.height);
this.drawPreampLine();
this.drawEqLine(); // This should paint on top of the preamp line
}
createColorPattern() {
const colorsCanvas = document.createElement('canvas');
const colorsCtx = colorsCanvas.getContext('2d');
colorsCanvas.width = this.bgImage.width * 2;
colorsCanvas.height = this.bgImage.height * 2;
colorsCtx.drawImage(this.bgImage, 0, 0, colorsCanvas.width, colorsCanvas.height);
this.colorPattern = this.canvasCtx.createPattern(colorsCanvas, 'repeat-x');
}
drawEqLine() {
const {props} = this;
const values = [
props.band60,
props.band170,
props.band310,
props.band600,
props.band1k,
props.band3k,
props.band6k,
props.band12k,
props.band14k,
props.band16k
];
this.canvasCtx.strokeStyle = this.colorPattern;
this.canvasCtx.lineWidth = 2;
this.canvasCtx.beginPath();
const paddingLeft = 4;
// TODO: Curve these lines
// TODO: Color these lines
values.forEach((value, i) => {
this.canvasCtx.lineTo(paddingLeft + (i * 16), getY(value));
});
this.canvasCtx.stroke();
}
drawPreampLine() {
const preampValue = getY(this.props.preamp);
this.canvasCtx.lineWidth = 2;
this.canvasCtx.strokeStyle = 'white';
this.canvasCtx.beginPath();
this.canvasCtx.moveTo(0, preampValue);
this.canvasCtx.lineTo(this.width, preampValue);
this.canvasCtx.stroke();
}
render() {
return <canvas
id='eqGraph'
ref='canvas'
width='152'
height='32'
/>;
}
}
export default connect((state) => state.equalizer.sliders)(EqGraph);

27
js/components/EqOn.jsx Normal file
View file

@ -0,0 +1,27 @@
import React from 'react';
import {connect} from 'react-redux';
import classnames from 'classnames';
class EqOn extends React.Component {
constructor(props) {
super(props);
this.handleClick = this.handleClick.bind(this);
}
handleClick() {
this.props.dispatch({type: 'TOGGLE_EQ_ON'});
}
render() {
const className = classnames({
selected: this.props.on
});
return <div
id='on'
className={className}
onClick={this.handleClick}
/>;
}
}
module.exports = connect((state) => state.equalizer)(EqOn);

View file

@ -4,54 +4,73 @@ import classnames from 'classnames';
import DraggableWindow from './DraggableWindow.jsx';
import Band from './Band.jsx';
import EqOn from './EqOn.jsx';
import EqAuto from './EqAuto.jsx';
import EqGraph from './EqGraph.jsx';
import '../../css/equalizer-window.css';
const EqualizerWindow = (props) => {
const {doubled} = props.display;
class EqualizerWindow extends React.Component {
constructor(props) {
super(props);
this.handleClick = this.handleClick.bind(this);
}
const className = classnames({
window: true,
doubled
});
return <DraggableWindow handleClass='title-bar'>
<div id='equalizer-window' className={className}>
<div className='equalizer-top title-bar' />
<div id='preamp'>
<Band band='preamp' />
</div>
<div id='band-60'>
<Band band='band60' />
</div>
<div id='band-170'>
<Band band='band170' />
</div>
<div id='band-310'>
<Band band='band310' />
</div>
<div id='band-600'>
<Band band='band600' />
</div>
<div id='band-1k'>
<Band band='band1k' />
</div>
<div id='band-3k'>
<Band band='band3k' />
</div>
<div id='band-6k'>
<Band band='band6k' />
</div>
<div id='band-12k'>
<Band band='band12k' />
</div>
<div id='band-14k'>
<Band band='band14k' />
</div>
<div id='band-16k'>
<Band band='band16k' />
</div>
</div>
</DraggableWindow>;
};
handleClick() {
this.props.dispatch({type: 'SET_FOCUSED_WINDOW', window: 'EQUALIZER'});
}
module.exports = connect((state) => state)(EqualizerWindow);
render() {
const {doubled} = this.props.display;
const className = classnames({
window: true,
selected: this.props.windows.focused === 'EQUALIZER',
doubled
});
return <DraggableWindow handleClass='title-bar'>
<div id='equalizer-window' className={className} onClick={this.handleClick}>
<div className='equalizer-top title-bar' />
<EqOn />
<EqAuto />
<EqGraph />
<div id='presets' />
<div id='preamp'>
<Band band='preamp' />
</div>
<div id='band-60'>
<Band band='band60' />
</div>
<div id='band-170'>
<Band band='band170' />
</div>
<div id='band-310'>
<Band band='band310' />
</div>
<div id='band-600'>
<Band band='band600' />
</div>
<div id='band-1k'>
<Band band='band1k' />
</div>
<div id='band-3k'>
<Band band='band3k' />
</div>
<div id='band-6k'>
<Band band='band6k' />
</div>
<div id='band-12k'>
<Band band='band12k' />
</div>
<div id='band-14k'>
<Band band='band14k' />
</div>
<div id='band-16k'>
<Band band='band16k' />
</div>
</div>
</DraggableWindow>;
}
}
module.exports = connect((state) => state)(EqualizerWindow);

View file

@ -25,74 +25,86 @@ import Volume from './Volume.jsx';
import '../../css/main-window.css';
const MainWindow = (props) => {
const {status} = props.media;
const {loading, doubled, shade, closed, llama} = props.display;
class MainWindow extends React.Component {
constructor(props) {
super(props);
this.handleClick = this.handleClick.bind(this);
}
const className = classnames({
window: true,
// TODO: Handle these status changes in the individual components
play: status === 'PLAYING',
stop: status === 'STOPPED',
pause: status === 'PAUSED',
loading,
doubled,
llama,
shade,
closed
});
handleClick() {
this.props.dispatch({type: 'SET_FOCUSED_WINDOW', window: 'MAIN'});
}
// TODO: Move this to an actionCreator
const handleDrop = (files) => {
props.winamp.loadFromFileReference(files[0]);
};
render() {
const {status} = this.props.media;
const {loading, doubled, shade, closed, llama} = this.props.display;
// NOTE: DragTarget but be outside Draggable Window, since currently
// DragTarget creates a wrapper DOM element which, since main-window is
// absolutely positioned, exists at a different location than the main
// window. Drag/Drop still work, because events propogate up to parent
// elements.
return <DragTarget handleFiles={handleDrop}>
<DraggableWindow handleClass='title-bar'>
<div id='main-window' className={className}>
<div id='loading'>Loading...</div>
<div id='title-bar' className='selected title-bar'>
<ContextMenu mediaPlayer={props.mediaPlayer} winamp={props.winamp} />
<ShadeTime />
<div id='minimize' />
<Shade />
<Close mediaPlayer={props.mediaPlayer} />
</div>
<div className='status'>
<ClutterBar />
<div id='play-pause' />
<div id='work-indicator' className={props.display.working ? 'selected' : ''} />
<Time />
<Visualizer analyser={props.mediaPlayer._analyser}/>
</div>
<div className='media-info'>
<Marquee />
<Kbps />
<Khz />
<MonoStereo />
</div>
<Volume mediaPlayer={props.mediaPlayer} />
<Balance mediaPlayer={props.mediaPlayer} />
<div className='windows'>
<div id='equalizer-button' />
<div id='playlist-button' />
</div>
<Position mediaPlayer={props.mediaPlayer} />
<ActionButtons mediaPlayer={props.mediaPlayer} />
<Eject winamp={props.winamp} />
<div className='shuffle-repeat'>
<Shuffle mediaPlayer={props.mediaPlayer} />
<Repeat mediaPlayer={props.mediaPlayer} />
</div>
<a id='about' target='blank' href='https://github.com/captbaritone/winamp2-js' />
</div>
</DraggableWindow>
</DragTarget>;
};
const className = classnames({
window: true,
// TODO: Handle these status changes in the individual components
play: status === 'PLAYING',
stop: status === 'STOPPED',
pause: status === 'PAUSED',
selected: this.props.windows.focused === 'MAIN',
loading,
doubled,
llama,
shade,
closed
});
module.exports = connect((state) => state)(MainWindow);
// TODO: Move this to an actionCreator
const handleDrop = (files) => {
this.props.winamp.loadFromFileReference(files[0]);
};
// NOTE: DragTarget but be outside Draggable Window, since currently
// DragTarget creates a wrapper DOM element which, since main-window is
// absolutely positioned, exists at a different location than the main
// window. Drag/Drop still work, because events propogate up to parent
// elements.
return <DragTarget handleFiles={handleDrop}>
<DraggableWindow handleClass='title-bar'>
<div id='main-window' className={className} onClick={this.handleClick}>
<div id='loading'>Loading...</div>
<div id='title-bar' className='selected title-bar'>
<ContextMenu mediaPlayer={this.props.mediaPlayer} winamp={this.props.winamp} />
<ShadeTime />
<div id='minimize' />
<Shade />
<Close mediaPlayer={this.props.mediaPlayer} />
</div>
<div className='status'>
<ClutterBar />
<div id='play-pause' />
<div id='work-indicator' className={this.props.display.working ? 'selected' : ''} />
<Time />
<Visualizer analyser={this.props.mediaPlayer._analyser}/>
</div>
<div className='media-info'>
<Marquee />
<Kbps />
<Khz />
<MonoStereo />
</div>
<Volume mediaPlayer={this.props.mediaPlayer} />
<Balance mediaPlayer={this.props.mediaPlayer} />
<div className='windows'>
<div id='equalizer-button' />
<div id='playlist-button' />
</div>
<Position mediaPlayer={this.props.mediaPlayer} />
<ActionButtons mediaPlayer={this.props.mediaPlayer} />
<Eject winamp={this.props.winamp} />
<div className='shuffle-repeat'>
<Shuffle mediaPlayer={this.props.mediaPlayer} />
<Repeat mediaPlayer={this.props.mediaPlayer} />
</div>
<a id='about' target='blank' href='https://github.com/captbaritone/winamp2-js' />
</div>
</DraggableWindow>
</DragTarget>;
}
}
module.exports = connect((state) => state)(MainWindow);

View file

@ -19,6 +19,20 @@ const userInput = (state, action) => {
}
};
const windows = (state, action) => {
if (!state) {
return {
focused: 'MAIN'
};
}
switch (action.type) {
case 'SET_FOCUSED_WINDOW':
return {...state, focused: action.window};
default:
return state;
}
};
const display = (state, action) => {
if (!state) {
return {
@ -87,24 +101,32 @@ const contextMenu = (state, action) => {
const equalizer = (state, action) => {
if (!state) {
return {
preamp: 50,
band60: 50,
band170: 50,
band310: 50,
band600: 50,
band1k: 50,
band3k: 50,
band6k: 50,
band12k: 50,
band14k: 50,
band16k: 50
on: false,
auto: false,
sliders: {
preamp: 50,
band60: 50,
band170: 50,
band310: 50,
band600: 50,
band1k: 50,
band3k: 50,
band6k: 50,
band12k: 50,
band14k: 50,
band16k: 50
}
};
}
switch (action.type) {
case 'SET_BAND_VALUE':
const newState = {...state};
newState[action.band] = action.value;
return newState;
const newSliders = {...state.sliders};
newSliders[action.band] = action.value;
return {...state, sliders: newSliders};
case 'TOGGLE_EQ_ON':
return {...state, on: !state.on};
case 'TOGGLE_EQ_AUTO':
return {...state, auto: !state.auto};
default:
return state;
}
@ -160,6 +182,7 @@ const media = (state, action) => {
const reducer = combineReducers({
userInput,
windows,
display,
contextMenu,
equalizer,

View file

@ -146,7 +146,19 @@ module.exports = [
{selectors: ['.selected .equalizer-top'], x: 0, y: 134, width: 275, height: 14},
{selectors: ['.band'], x: 13, y: 164, width: 209, height: 129},
{selectors: ['.band input::-webkit-slider-thumb', 'band input::-moz-range-thumb'], x: 0, y: 164, width: 11, height: 11},
{selectors: ['band input::-webkit-slider-thumb:active', '.band input::-moz-range-thumb:active'], x: 0, y: 176, width: 11, height: 11}
{selectors: ['band input::-webkit-slider-thumb:active', '.band input::-moz-range-thumb:active'], x: 0, y: 176, width: 11, height: 11},
{selectors: ['#on'], x: 10, y: 119, width: 26, height: 12},
{selectors: ['#on:active'], x: 128, y: 119, width: 26, height: 12},
{selectors: ['#on.selected'], x: 69, y: 119, width: 26, height: 12},
{selectors: ['#on.selected:active'], x: 187, y: 119, width: 26, height: 12},
{selectors: ['#auto'], x: 36, y: 119, width: 32, height: 12},
{selectors: ['#auto:active'], x: 154, y: 119, width: 32, height: 12},
{selectors: ['#auto.selected'], x: 95, y: 119, width: 32, height: 12},
{selectors: ['#auto.selected:active'], x: 213, y: 119, width: 32, height: 12},
{selectors: ['#eqGraph'], x: 0, y: 294, width: 113, height: 19},
{selectors: ['#presets'], x: 224, y: 164, width: 44, height: 12},
{selectors: ['#presets:active'], x: 224, y: 176, width: 44, height: 12},
{name: 'PREAMP_LINE', selectors: ['#preamp-line'], x: 0, y: 314, width: 113, height: 1}
]
},
{
@ -182,7 +194,7 @@ module.exports = [
name: 'TITLEBAR',
sprites: [
{selectors: ['#title-bar'], x: 27, y: 15, width: 275, height: 14},
{selectors: ['#title-bar.selected'], x: 27, y: 0, width: 275, height: 14},
{selectors: ['.selected #title-bar'], x: 27, y: 0, width: 275, height: 14},
{selectors: ['.llama #title-bar'], x: 27, y: 61, width: 275, height: 14},
{selectors: ['.llama #title-bar.selected'], x: 27, y: 57, width: 275, height: 14},
{selectors: ['#title-bar #option'], x: 0, y: 0, width: 9, height: 9},