diff options
Diffstat (limited to 'app')
| -rw-r--r-- | app/client/common/button.component.js | 2 | ||||
| -rw-r--r-- | app/client/common/checkbox.component.js | 41 | ||||
| -rw-r--r-- | app/client/common/index.js | 3 | ||||
| -rw-r--r-- | app/client/common/select.component.js | 2 | ||||
| -rw-r--r-- | app/client/common/slider.component.js | 16 | ||||
| -rw-r--r-- | app/client/modules/index.js | 3 | ||||
| -rw-r--r-- | app/client/modules/module.reducer.js | 2 | ||||
| -rw-r--r-- | app/client/modules/morph/index.js | 37 | ||||
| -rw-r--r-- | app/client/modules/morph/morph.actions.js | 45 | ||||
| -rw-r--r-- | app/client/modules/morph/morph.module.js | 7 | ||||
| -rw-r--r-- | app/client/modules/morph/morph.reducer.js | 35 | ||||
| -rw-r--r-- | app/client/modules/morph/morph.tasks.js | 23 | ||||
| -rw-r--r-- | app/client/modules/morph/views/morph.app.js | 185 | ||||
| -rw-r--r-- | app/client/socket/socket.task.js | 1 | ||||
| -rw-r--r-- | app/client/types.js | 3 |
15 files changed, 398 insertions, 7 deletions
diff --git a/app/client/common/button.component.js b/app/client/common/button.component.js index 21aa5b6..65cd5f6 100644 --- a/app/client/common/button.component.js +++ b/app/client/common/button.component.js @@ -19,7 +19,7 @@ class Button extends Component { <button onClick={this.handleClick} > - {this.props.children} + {this.props.value || this.props.children} </button> </label> </div> diff --git a/app/client/common/checkbox.component.js b/app/client/common/checkbox.component.js new file mode 100644 index 0000000..2d808c2 --- /dev/null +++ b/app/client/common/checkbox.component.js @@ -0,0 +1,41 @@ +import { h, Component } from 'preact' +import { connect } from 'react-redux' +import { bindActionCreators } from 'redux' +import * as liveActions from '../live/live.actions' + +class Checkbox extends Component { + constructor(props){ + super(props) + this.handleClick = this.handleClick.bind(this) + } + handleClick(e){ + clearTimeout(this.timeout) + let new_value = e.target.checked + this.props.onToggle && this.props.onToggle(new_value) + } + render() { + const checked = this.props.value + const dim = !this.props.noDim + return ( + <div className='checkbox param'> + <label> + <span>{this.props.title}</span> + <input + type='checkbox' + onClick={this.handleClick} + checked={checked} + /> + </label> + </div> + ) + } +} + +const mapStateToProps = state => ({ +}) + +const mapDispatchToProps = (dispatch, ownProps) => ({ + // actions: bindActionCreators(liveActions, dispatch) +}) + +export default connect(mapStateToProps, mapDispatchToProps)(Checkbox) diff --git a/app/client/common/index.js b/app/client/common/index.js index 6db1184..3981fa7 100644 --- a/app/client/common/index.js +++ b/app/client/common/index.js @@ -1,4 +1,5 @@ import Button from './button.component' +import Checkbox from './checkbox.component' import CurrentTask from './currentTask.component' import { FileList, FileRow } from './fileList.component' import FileUpload from './fileUpload.component' @@ -22,6 +23,6 @@ export { FolderList, FileList, FileRow, FileUpload, Gallery, Player, Group, ParamGroup, Param, - TextInput, Slider, Select, Button, + TextInput, Slider, Select, Button, Checkbox, CurrentTask, }
\ No newline at end of file diff --git a/app/client/common/select.component.js b/app/client/common/select.component.js index 3fc13c2..d08ae60 100644 --- a/app/client/common/select.component.js +++ b/app/client/common/select.component.js @@ -18,7 +18,7 @@ class Select extends Component { const options = (this.props.options || []).map((key,i) => { let name, value if (typeof key === 'string') { - name = key.length < 4 ? key.toUpperCase() : key + name = key.length < 2 ? key.toUpperCase() : key value = key } else if (typeof key === 'object') { diff --git a/app/client/common/slider.component.js b/app/client/common/slider.component.js index cc00650..468debd 100644 --- a/app/client/common/slider.component.js +++ b/app/client/common/slider.component.js @@ -52,6 +52,9 @@ class Slider extends Component { if (this.props.type === 'odd') { new_value = parseInt(Math.floor(new_value / 2) * 2 + 1) } + if (this.props.type === 'list') { + new_value = this.props.options[new_value] || this.props.options[0] + } this.setState({ value: new_value }) this.timeout = setTimeout(() => { this.props.live && this.props.actions.set_param(this.props.name, new_value) @@ -66,8 +69,17 @@ class Slider extends Component { } let text_value = value let step; + let min = this.props.min || 0 + let max = this.props.max || 0 if (this.props.type === 'int') { step = 1 + } else if (this.props.type === 'list') { + min = 0 + max = this.props.options.length-1 + step = 1 + console.log('old', value) + value = this.props.options.indexOf(value) + console.log('new', value, this.props.options[value]) } else { step = (this.props.max - this.props.min) / 100 text_value = parseFloat(value).toFixed(2) @@ -80,8 +92,8 @@ class Slider extends Component { </label> <input type='range' - min={this.props.min} - max={this.props.max} + min={min} + max={max} step={step} value={value} onInput={this.handleRange} diff --git a/app/client/modules/index.js b/app/client/modules/index.js index 6cc6cd4..14a2333 100644 --- a/app/client/modules/index.js +++ b/app/client/modules/index.js @@ -1,8 +1,9 @@ +import morph from './morph' import pix2pix from './pix2pix' import pix2pixhd from './pix2pixhd' import pix2wav from './pix2wav' import samplernn from './samplernn' export default { - pix2pix, pix2pixhd, pix2wav, samplernn + morph, pix2pix, pix2pixhd, pix2wav, samplernn } diff --git a/app/client/modules/module.reducer.js b/app/client/modules/module.reducer.js index 0598960..ff977ce 100644 --- a/app/client/modules/module.reducer.js +++ b/app/client/modules/module.reducer.js @@ -1,11 +1,13 @@ import { combineReducers } from 'redux' +import morphReducer from './morph/morph.reducer' import pix2pixReducer from './pix2pix/pix2pix.reducer' import pix2pixhdReducer from './pix2pixhd/pix2pixhd.reducer' import pix2wavReducer from './pix2wav/pix2wav.reducer' import samplernnReducer from './samplernn/samplernn.reducer' export const moduleReducer = combineReducers({ + morph: morphReducer, pix2pix: pix2pixReducer, pix2pixhd: pix2pixhdReducer, pix2wav: pix2wavReducer, diff --git a/app/client/modules/morph/index.js b/app/client/modules/morph/index.js new file mode 100644 index 0000000..9c90848 --- /dev/null +++ b/app/client/modules/morph/index.js @@ -0,0 +1,37 @@ +import { h, Component } from 'preact' +import { Route, Link } from 'react-router-dom' + +import actions from '../../actions' + +import util from '../../util' + +import MorphApp from './views/morph.app' + +class router { + componentWillMount(){ + actions.system.changeTool('morph') + document.body.style.backgroundImage = 'linear-gradient(' + (util.randint(40)+40) + 'deg, #def, #dfe)' + } + componentWillReceiveProps(){ + actions.system.changeTool('morph') + document.body.style.backgroundImage = 'linear-gradient(' + (util.randint(40)+40) + 'deg, #def, #dfe)' + } + render(){ + return ( + <section> + <Route exact path='/morph/app/' component={MorphApp} /> + </section> + ) + } +} + +function links(){ + return [ + { url: '/morph/app/', name: 'morph' }, + ] +} + +export default { + name: 'morph', + router, links, +} diff --git a/app/client/modules/morph/morph.actions.js b/app/client/modules/morph/morph.actions.js new file mode 100644 index 0000000..9d47d03 --- /dev/null +++ b/app/client/modules/morph/morph.actions.js @@ -0,0 +1,45 @@ +import uuidv1 from 'uuid/v1' + +import socket from '../../socket' +import types from '../../types' + +import * as datasetLoader from '../../dataset/dataset.loader' + +import actions from '../../actions' + +import util from '../../util' + +import morphModule from './morph.module' + +export const load_data = (id) => (dispatch) => { + const module = morphModule.name + util.allProgress([ + datasetLoader.load(module), + actions.socket.list_sequences({ module: 'pix2pixhd', dir: 'sequences' }), + actions.socket.list_directory({ module, dir: 'renders' }), + ], (percent, i, n) => { + console.log('morph load progress', i, n) + dispatch({ type: types.app.load_progress, progress: { i, n }}) + }).then(res => { + const [datasetApiReport, sequences, renders] = res + const { + folderLookup, + fileLookup, + datasetLookup, + folders, + files, + unsortedFolder, + resultsFolder, + } = datasetApiReport + + dispatch({ + type: types.morph.load, + data: datasetApiReport, + app: { + files, + sequences, + renders, + } + }) + }) +}
\ No newline at end of file diff --git a/app/client/modules/morph/morph.module.js b/app/client/modules/morph/morph.module.js new file mode 100644 index 0000000..8fc5ce4 --- /dev/null +++ b/app/client/modules/morph/morph.module.js @@ -0,0 +1,7 @@ +const morphModule = { + name: 'morph', + displayName: 'Morph', + datatype: 'video', +} + +export default morphModule diff --git a/app/client/modules/morph/morph.reducer.js b/app/client/modules/morph/morph.reducer.js new file mode 100644 index 0000000..92cbc9e --- /dev/null +++ b/app/client/modules/morph/morph.reducer.js @@ -0,0 +1,35 @@ +import types from '../../types' +import datasetReducer from '../../dataset/dataset.reducer' + +const morphInitialState = { + loading: true, + progress: { i: 0, n: 0 }, + error: null, + folder_id: 0, + data: null, + app: null, +} + +const morphReducer = (state = morphInitialState, action) => { + if (action.data && action.data.module === 'morph') { + state = datasetReducer(state, action) + } + + switch (action.type) { + case types.morph.load_results: + return { + ...state, + results: action.results, + } + case types.morph.load: + console.log('morph load', action.app) + return { + ...state, + app: action.app, + } + default: + return state + } +} + +export default morphReducer diff --git a/app/client/modules/morph/morph.tasks.js b/app/client/modules/morph/morph.tasks.js new file mode 100644 index 0000000..67abc8a --- /dev/null +++ b/app/client/modules/morph/morph.tasks.js @@ -0,0 +1,23 @@ +import uuidv1 from 'uuid/v1' + +import socket from '../../socket' +import types from '../../types' + +import actions from '../../actions' + +import module from './morph.module' + +export const fetch_task = (url, file_id, dataset) => dispatch => { + if (! url) return console.log('input file inaccessible (no url)') + const task = { + module: module.name, + activity: 'fetch', + dataset: dataset, + opt: { + url, + file_id, + dataset, + } + } + return actions.queue.add_task(task) +} diff --git a/app/client/modules/morph/views/morph.app.js b/app/client/modules/morph/views/morph.app.js new file mode 100644 index 0000000..045f396 --- /dev/null +++ b/app/client/modules/morph/views/morph.app.js @@ -0,0 +1,185 @@ +import { h, Component } from 'preact' +import { bindActionCreators } from 'redux' +import { Link } from 'react-router-dom'; +import { connect } from 'react-redux' +import util from '../../../util' + +import actions from '../../../actions' + +import * as morphActions from '../morph.actions' +import * as morphTasks from '../morph.tasks' + +import Loading from '../../../common/loading.component' +import { + Select, Slider, Checkbox, Group, + Button, Param, FileList, FileRow, +} from '../../../common' + +let yes_count = 0 + +class MorphResults extends Component { + constructor(props){ + super() + this.state = { + a: "", + b: "", + a_offset: 0, + b_offset: 0, + steps: 16, + dilate: 2, + smooth: true, + cmd: 'mix', + } + if (!props.morph.data) props.actions.load_data() + } + componentDidMount(){ + yes_count = 0 + } + render(){ + if (! this.props.morph.app) return <Loading progress={this.props.morph.progress} /> + + const { sequences, renders, files } = this.props.morph.app + const sequence_options = sequences.map(sequence => [ + sequence.name.split("_").slice(0, 3).join(" ") + "~ (" + sequence.count + ")", + sequence.name + ]) + + console.log(sequence_options) + const totalLength = (this.state.steps * this.state.dilate) / 25 + let lengthWarning + if (this.state.steps > 64) { + lengthWarning = ( + <span><br/>warning, this may take a while</span> + ) + } + + return ( + <div className='app morph'> + <div className='heading row middle'> + <h1>Morph</h1> + </div> + <div class='rows params renders'> + <div class='column'> + <Group title="From"> + <Select + title="Starting sequence" + value={this.state.a} + options={sequence_options} + onChange={key => this.setState({ a: key })} + /> + <Slider + title="Offset" + value={this.state.a_offset} + min={0} max={1} step={0.01} + onChange={key => this.setState({ a_offset: key })} + /> + </Group> + + <Group title="To"> + <Select + title="Ending sequence" + value={this.state.b} + options={sequence_options} + onChange={key => this.setState({ b: key })} + /> + <Slider + title="Offset" + value={this.state.b_offset} + min={0} max={1} step={0.01} + onChange={key => this.setState({ b_offset: key })} + /> + </Group> + + <Group title="Morph Settings"> + <Select + title="Action" + value={this.state.cmd} + options={['mix', 'average']} + onChange={key => this.setState({ a: key })} + /> + <Slider + type="list" + title="Steps" + value={this.state.steps} + options={[2,4,8,16,32,64,128,256]} + onChange={key => this.setState({ steps: key })} + /> + <Slider + type="list" + title="Dilate" + value={this.state.dilate} + options={[2,4,8,16,32]} + onChange={key => this.setState({ dilate: key })} + /> + <Checkbox + title="Smooth" + value={this.state.smooth} + onToggle={key => this.setState({ smooth: key })} + /> + <Button + title="Run morph" + value="Go" + /> + <br /> + <Param title="Total length"> + {totalLength.toFixed(1) + " seconds"} + </Param> + {lengthWarning} + <br /> + </Group> + </div> + + <FileList + linkFiles + files={files} + orderBy='date desc' + fields={'name date size delete'} + onDelete={file => { + let yes; + if (yes_count < 3) { + yes = confirm('Are you sure you want to delete this file?') + } else { + yes = true + } + if (yes) { + yes_count += 1 + console.log('delete: confirmed') + actions.file.destroy(file) + } + }} + /> + <br /> + + <h3>renders on server</h3> + <FileList + files={renders} + orderBy='date desc' + fields={'name date size'} + onClick={(file, e) => { + e.preventDefault() + e.stopPropagation() + console.log('picked a result', file) + this.handlePick(file) + }} + /> + + </div> + </div> + ) + } + handlePick(file){ + // this.props.audioPlayer.play(file) + } +} + +const mapStateToProps = state => ({ + morph: state.module.morph, +}) + +const mapDispatchToProps = (dispatch, ownProps) => ({ + actions: bindActionCreators(morphActions, dispatch), + remote: bindActionCreators(morphTasks, dispatch), + // audioPlayer: bindActionCreators(audioPlayerActions, dispatch), +}) + +export default connect(mapStateToProps, mapDispatchToProps)(MorphResults) diff --git a/app/client/socket/socket.task.js b/app/client/socket/socket.task.js index 1b33cd9..18f88cf 100644 --- a/app/client/socket/socket.task.js +++ b/app/client/socket/socket.task.js @@ -7,7 +7,6 @@ let finishTimeout; socket.on('task_res', (raw_data) => { // does not like the nested task object for some reason.. - console.log(typeof raw_data) let data; try { if (typeof raw_data === 'string') { diff --git a/app/client/types.js b/app/client/types.js index e710248..c41a03d 100644 --- a/app/client/types.js +++ b/app/client/types.js @@ -115,5 +115,8 @@ export default { ]), dashboard: with_type('dashboard', [ 'load', + ]), + morph: with_type('morph', [ + 'load', ]) } |
