import update from 'react-addons-update'; import * as contextTools from '../constants/contextTools.js'; import { COLOR_STRING_TO_HEX, COLOR_HEX_TO_STRING } from '../constants/general.js'; import { ERASER_SIZES, BRUSH_SIZES } from '../constants/d2Constants.js'; import { SHAPE_TYPE_PROPERTIES } from '../constants/shapeTypeProperties.js'; import * as actions from '../actions/index.js'; import { select } from './menusReducer.js'; import { getSelectedObjectsSelector, getBoundingBox } from '../utils/selectionUtils.js'; import { Matrix } from 'cal'; import { updateTool as updateTool2d } from './d2/toolReducer.js'; import { updateColor } from './selectionReducer.js'; export default function (state, action) { switch (action.category) { case actions.CAT_SELECTION: { let menus = state.menus; const [firstSelected] = state.selection.objects; const isSolid = firstSelected ? state.objectsById[firstSelected.id].solid : true; const color = isSolid ? contextTools.PIPETTE : contextTools.HOLE_MATERIAL; menus = select(menus, color); const fillBool = firstSelected && state.objectsById[firstSelected.id].fill; const fill = fillBool ? contextTools.FILL_TOGGLE_FILL : contextTools.FILL_TOGGLE_OUTLINE; menus = select(menus, fill); return update(state, { menus: { $set: menus } }); } default: break; } switch (action.type) { case actions.D2_CHANGE_TOOL: { const color = state.context.solid ? contextTools.PIPETTE : contextTools.HOLE_MATERIAL; return update(state, { menus: { $set: select(state.menus, color) } }); } default: break; } switch (action.tool) { case contextTools.PIPETTE: { state = update(state, { context: { lastTool: { $set: state.d2.tool } } }); state = updateTool2d(state, contextTools.PIPETTE); return state; } case contextTools.HOLE_MATERIAL: { return update(state, { objectsById: state.selection.objects.reduce((updateObject, { id }) => { updateObject[id] = { solid: { $set: false } }; return updateObject; }, {}), context: { solid: { $set: false } } }); } case contextTools.LIGHT_BLUE: case contextTools.LIGHT_GREEN: case contextTools.LIGHT_PINK: case contextTools.LIGHT_YELLOW: case contextTools.BLUE: case contextTools.GREEN: case contextTools.PINK: case contextTools.YELLOW: case contextTools.DARK_BLUE: case contextTools.DARK_GREEN: case contextTools.DARK_PINK: case contextTools.DARK_YELLOW: { const color = COLOR_STRING_TO_HEX[action.tool]; return updateColor(state, color); } case contextTools.ERASER_SIZE_SMALL: case contextTools.ERASER_SIZE_MEDIUM: case contextTools.ERASER_SIZE_LARGE: { const size = ERASER_SIZES[action.tool]; return update(state, { d2: { eraser: { size: { $set: size } } } }); } case contextTools.BRUSH_SIZE_SMALL: case contextTools.BRUSH_SIZE_MEDIUM: case contextTools.BRUSH_SIZE_LARGE: { const size = BRUSH_SIZES[action.tool]; return update(state, { d2: { brush: { size: { $set: size } } } }); } case contextTools.FILL_TOGGLE_FILL: case contextTools.FILL_TOGGLE_OUTLINE: { const fill = action.tool === contextTools.FILL_TOGGLE_FILL; return update(state, { objectsById: state.selection.objects.reduce((updateObject, { id }) => { const { type } = state.objectsById[id]; const d3Visible = SHAPE_TYPE_PROPERTIES[type].D3Visible; if (d3Visible) updateObject[id] = { fill: { $set: fill } }; return updateObject; }, {}) }); } case contextTools.ALIGN_LEFT: case contextTools.ALIGN_HORIZONTAL: case contextTools.ALIGN_RIGHT: case contextTools.ALIGN_TOP: case contextTools.ALIGN_VERTICAL: case contextTools.ALIGN_BOTTOM: { if (state.selection.objects < 2) return state; const selection = state.selection; const selectedShapeDatas = getSelectedObjectsSelector(selection.objects, state.objectsById); const totalBoundingBox = getBoundingBox(selectedShapeDatas); for (const shapeData of selectedShapeDatas) { const boundingBox = getBoundingBox([shapeData]); let deltaX = 0; let deltaY = 0; switch (action.tool) { case contextTools.ALIGN_LEFT: deltaX = totalBoundingBox.min.x - boundingBox.min.x; break; case contextTools.ALIGN_HORIZONTAL: deltaX = totalBoundingBox.center.x - boundingBox.center.x; break; case contextTools.ALIGN_RIGHT: deltaX = totalBoundingBox.max.x - boundingBox.max.x; break; case contextTools.ALIGN_TOP: deltaY = totalBoundingBox.min.z - boundingBox.min.z; break; case contextTools.ALIGN_VERTICAL: deltaY = totalBoundingBox.center.y - boundingBox.center.y; break; case contextTools.ALIGN_BOTTOM: deltaY = totalBoundingBox.max.z - boundingBox.max.z; break; default: break; } const transform = state.objectsById[shapeData.UID].transform.translate(deltaX, deltaY); state = update(state, { objectsById: { [shapeData.UID]: { transform: { $set: transform } } }, selection: { objects: { [selection.objects.findIndex(({ id }) => id === shapeData.UID)]: { initialTransform: { $set: transform } } } } }); } state = update(state, { selection: { transform: { $set: new Matrix() } } }); return state; } default: return state; } }