Doodle3D-Core/src/reducer/index.js

287 lines
7.9 KiB
JavaScript

import * as THREE from 'three';
import undoable from 'redux-undo';
import undoFilter from '../utils/undoFilter.js';
import * as actions from '../actions/index.js';
import * as d2Tools from '../constants/d2Tools.js';
import * as d3Tools from '../constants/d3Tools.js';
import { COLOR_STRING_TO_HEX, FONT_FACE } from '../constants/general.js';
import * as contextTools from '../constants/contextTools.js';
import { ERASER_SIZES, BRUSH_SIZES } from '../constants/d2Constants.js';
import update from 'react-addons-update';
import { defaultCamera } from './d3/tools/cameraReducer.js';
import d2AddImageReducer from './d2/addImageReducer.js';
import d2ToolReducer from './d2/toolReducer.js';
import d3ToolReducer from './d3/toolReducer.js';
import d2PinchZoomReducer from './d2/pinchZoomReducer.js';
import d2WheelZoomReducer from './d2/wheelZoomReducer.js';
import d2PanZoomReducer from './d2/panReducer.js';
import selectionReducer from './selectionReducer.js';
import selectionOperationReducer from './selectionOperationReducer.js';
import contextReducer from './contextReducer.js';
import { Matrix, Vector } from '@doodle3d/cal';
import { setActiveSpace, addSpaceActive, setActive2D, getActive2D, addObject } from './objectReducers.js';
import menusReducer from './menusReducer.js';
// import createDebug from 'debug';
// const debug = createDebug('d3d:reducer:sketcher');
const initialState = {
spaces: {
world: {
matrix: new THREE.Matrix4(),
objectIds: []
}
},
objectsById: {},
activeSpace: 'world',
objectIdCounter: 0,
context: {
solid: true,
color: COLOR_STRING_TO_HEX[contextTools.LIGHT_BLUE_B],
font: FONT_FACE[contextTools.OSWALD]
},
selection: {
transform: new Matrix(),
// array of objects (one per selected object),
// containing the object id and it's initialTransform (pre selection transform)
objects: []
},
d2: {
brush: {
size: BRUSH_SIZES[contextTools.BRUSH_SIZE_MEDIUM]
},
eraser: {
active: false,
size: ERASER_SIZES[contextTools.ERASER_SIZE_MEDIUM]
},
transform: {
active: false,
handle: '',
dragSelect: {
start: new Vector(),
end: new Vector()
}
},
trace: {
start: new Vector(),
position: new Vector(),
active: false,
floodFillData: {
edge: [],
fill: []
}
},
tool: d2Tools.FREE_HAND,
toolbar: {
open: []
},
canvasMatrix: new Matrix()
},
d3: {
height: {
handle: '',
active: false
},
twist: {
rotation: 0,
active: false
},
sculpt: {
handles: [],
activeHandle: null
},
tool: d3Tools.HEIGHT,
toolbar: {
open: []
},
camera: defaultCamera
},
menus: menusReducer(undefined, {}),
preventScroll: true,
disableScroll: false
};
function sketcherReducer(state = initialState, action) {
// if (action.log !== false) debug(action.type);
switch (action.category) {
case actions.CAT_SELECTION:
const preSelectionState = state;
state = selectionReducer(state, action);
// if selection changed
if (state.selection.objects !== preSelectionState.selection.objects) {
state = d2ToolReducer(state, action);
state = d3ToolReducer(state, action);
state = updateMenus(state, action);
state = contextReducer(state, action);
}
return state;
default:
break;
}
switch (action.type) {
case actions.ADD_OBJECT:
return addObject(state, action.objectData);
case actions.D2_DRAG_START:
case actions.D2_DRAG:
case actions.D2_DRAG_END:
case actions.D2_TAP:
case actions.TRACE_DRAG:
case actions.TRACE_DRAG_END:
case actions.TRACE_TAP:
case `${actions.FLOOD_FILL}_PENDING`:
case `${actions.FLOOD_FILL}_FULFILLED`:
case `${actions.FLOOD_FILL}_REJECTED`:
case `${actions.TRACE_FLOOD_FILL}_PENDING`:
case `${actions.TRACE_FLOOD_FILL}_FULFILLED`:
case `${actions.TRACE_FLOOD_FILL}_REJECTED`:
case actions.TRANSFORM_START:
case actions.TRANSFORM:
case actions.TRANSFORM_END:
case actions.MULTITOUCH_TRANSFORM_START:
case actions.MULTITOUCH_TRANSFORM:
case actions.MULTITOUCH_TRANSFORM_END:
case actions.D2_TEXT_INIT:
case actions.D2_TEXT_INPUT_CHANGE:
case actions.MOVE_SELECTION:
return d2ToolReducer(state, action);
case `${actions.ADD_IMAGE}_FULFILLED`:
return d2AddImageReducer(state, action);
case actions.D2_MOUSE_WHEEL:
return d2WheelZoomReducer(state, action);
case actions.D2_SECOND_DRAG:
return d2PanZoomReducer(state, action);
case actions.D2_MULTITOUCH_START:
case actions.D2_MULTITOUCH:
case actions.D2_MULTITOUCH_END:
state = d2ToolReducer(state, action);
state = d2PinchZoomReducer(state, action);
return state;
case actions.D3_DRAG_START:
case actions.D3_DRAG:
case actions.D3_DRAG_END:
case actions.D3_SECOND_DRAG_START:
case actions.D3_SECOND_DRAG:
case actions.D3_SECOND_DRAG_END:
case actions.D3_TAP:
case actions.D3_MOUSE_WHEEL:
case actions.D3_MULTITOUCH_START:
case actions.D3_MULTITOUCH:
case actions.D3_MULTITOUCH_END:
case actions.HEIGHT_START:
case actions.HEIGHT:
case actions.HEIGHT_END:
case actions.TWIST_START:
case actions.TWIST:
case actions.TWIST_END:
case actions.SCULPT_START:
case actions.SCULPT:
case actions.SCULPT_END:
case actions.ADD_SCULPT_HANDLE:
case actions.REMOVE_SCULPT_HANDLE:
case actions.STAMP:
return d3ToolReducer(state, action);
case actions.D2_CHANGE_TOOL:
state = selectionReducer(state, action);
state = d2ToolReducer(state, action); // switch and initialize tool
state = updateMenus(state, action);
state = contextReducer(state, action);
state = setActive2D(state, null);
return state;
case actions.D3_CHANGE_TOOL:
state = d3ToolReducer(state, action); // switch and initialize tool
state = updateMenus(state, action);
return state;
case actions.CONTEXT_CHANGE_TOOL:
state = contextReducer(state, action);
state = updateMenus(state, action);
return state;
case actions.CLEAR:
return update(initialState, {});
case actions.OPEN_SKETCH:
let first = true;
const { spaces } = action.data.data;
for (const space of spaces) {
if (first) {
if (!state.spaces.world) state = addSpaceActive(state, space.matrix, 'world');
} else {
state = addSpaceActive(state, space.matrix);
}
for (const object of space.objects) {
if (first) {
state = addObject(state, { ...object, space: 'world' });
} else {
state = addObject(state, object);
}
}
first = false;
}
return setActiveSpace(state, 'world');
case actions.DUPLICATE_SELECTION:
case actions.DELETE_SELECTION:
case actions.UNION:
case actions.INTERSECT:
return selectionOperationReducer(state, action);
case actions.MENU_OPEN:
case actions.MENU_CLOSE:
return updateMenus(state, action);
case actions.UPDATE_MATRIX:
return update(state, {
objectsById: { [action.id]: { transform: { $set: action.transform } } }
});
case actions.SET_PREVENT_SCROLL:
return update(state, {
preventScroll: { $set: action.preventScroll }
});
case actions.SET_DISABLE_SCROLL:
return update(state, {
disableScroll: { $set: action.disableScroll }
});
default:
return state;
}
}
export default undoable(sketcherReducer, {
filter: undoFilter,
initTypes: []
// debug: true
});
function updateMenus(state, action) {
return {
...state,
menus: menusReducer(state.menus, action)
};
}
export function getD2ActiveShape(state) {
return getActive2D(state);
}
export function isEmpty(state) {
return Object.keys(state.sketcher.present.objectsById).length === 0;
}