forked from ppfun/pixelplanet
hook up settings
This commit is contained in:
parent
47b4db2602
commit
ff7ec9b0e9
|
@ -3,21 +3,38 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import React, { useState, useCallback, useRef } from 'react';
|
import React, { useState, useCallback, useRef } from 'react';
|
||||||
import { useSelector } from 'react-redux';
|
import { useSelector, useDispatch, shallowEqual } from 'react-redux';
|
||||||
import fileDownload from 'js-file-download';
|
import fileDownload from 'js-file-download';
|
||||||
import { t } from 'ttag';
|
import { c, t } from 'ttag';
|
||||||
|
|
||||||
import TemplateItem from './TemplateItem';
|
import TemplateItem from './TemplateItem';
|
||||||
import TemplateItemEdit from './TemplateItemEdit';
|
import TemplateItemEdit from './TemplateItemEdit';
|
||||||
|
import SettingsItem from './SettingsItem';
|
||||||
import templateLoader from '../ui/templateLoader';
|
import templateLoader from '../ui/templateLoader';
|
||||||
|
import {
|
||||||
|
toggleOVEnabled,
|
||||||
|
toggleSmallPxls,
|
||||||
|
setOvOpacity,
|
||||||
|
} from '../store/actions/templates';
|
||||||
|
|
||||||
|
|
||||||
const TemplateSettings = () => {
|
const TemplateSettings = () => {
|
||||||
const [showAdd, setShowAdd] = useState(false);
|
const [showAdd, setShowAdd] = useState(false);
|
||||||
const list = useSelector((state) => state.templates.list);
|
const [
|
||||||
|
list,
|
||||||
|
oVEnabled,
|
||||||
|
oSmallPxls,
|
||||||
|
oOpacity,
|
||||||
|
] = useSelector((state) => [
|
||||||
|
state.templates.list,
|
||||||
|
state.templates.ovEnabled,
|
||||||
|
state.templates.oSmallPxls,
|
||||||
|
state.templates.oOpacity,
|
||||||
|
], shallowEqual);
|
||||||
const [editingIndices, setEditingIndices] = useState([]);
|
const [editingIndices, setEditingIndices] = useState([]);
|
||||||
const close = useCallback(() => setShowAdd(false), []);
|
const close = useCallback(() => setShowAdd(false), []);
|
||||||
const importRef = useRef();
|
const importRef = useRef();
|
||||||
|
const dispatch = useDispatch();
|
||||||
|
|
||||||
const toggleEditing = useCallback((title) => {
|
const toggleEditing = useCallback((title) => {
|
||||||
const index = list.findIndex((t) => t.title === title);
|
const index = list.findIndex((t) => t.title === title);
|
||||||
|
@ -32,10 +49,48 @@ const TemplateSettings = () => {
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<h3>{t`Templates`}</h3>
|
<h2>{t`Templates`}</h2>
|
||||||
<p>
|
<p>
|
||||||
{t`Tired of always spaming one single color? Want to create art instead, but you have to count pixels from some other image? Templates can help you with that! Templates can show as overlay and you can draw over them. One pixel on the template, should be one pixel on the canvas.`}
|
{t`Tired of always spaming one single color? Want to create art instead, but you have to count pixels from some other image? Templates can help you with that! Templates can show as overlay and you can draw over them. One pixel on the template, should be one pixel on the canvas.`}
|
||||||
</p>
|
</p>
|
||||||
|
<SettingsItem
|
||||||
|
title={t`Enable Overlay`}
|
||||||
|
keyBind={c('keybinds').t`T`}
|
||||||
|
value={oVEnabled}
|
||||||
|
onToggle={() => dispatch(toggleOVEnabled())}
|
||||||
|
>
|
||||||
|
{t`Show templates as overlays ingame.`}
|
||||||
|
</SettingsItem>
|
||||||
|
<SettingsItem
|
||||||
|
title={t`Small Pixels Overlay`}
|
||||||
|
value={oSmallPxls}
|
||||||
|
deactivated={!oVEnabled}
|
||||||
|
onToggle={() => dispatch(toggleSmallPxls())}
|
||||||
|
>
|
||||||
|
{t`Show overlay as small individual pixels (will only show in high zoomlevels).`}
|
||||||
|
</SettingsItem>
|
||||||
|
|
||||||
|
<div className="setitem">
|
||||||
|
<div className="setrow">
|
||||||
|
<h3 className="settitle">
|
||||||
|
{t`Overlay Opacity`}
|
||||||
|
</h3>
|
||||||
|
<div style={{ textAlign: 'right' }}>
|
||||||
|
<input
|
||||||
|
type="number"
|
||||||
|
value={oOpacity}
|
||||||
|
style={{ maxWidth: '6em' }}
|
||||||
|
step="1"
|
||||||
|
min="10"
|
||||||
|
max="100"
|
||||||
|
onChange={(evt) => dispatch(setOvOpacity(evt.target.value))}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div className="modaldesc">{t`Opacity of Overlay in percent.`}</div>
|
||||||
|
<div className="modaldivider" />
|
||||||
|
</div>
|
||||||
|
|
||||||
<div className="content">
|
<div className="content">
|
||||||
{list.map(({
|
{list.map(({
|
||||||
enabled, imageId, canvasId, title, x, y, width, height,
|
enabled, imageId, canvasId, title, x, y, width, height,
|
||||||
|
|
|
@ -16,9 +16,11 @@ const PencilButton = () => {
|
||||||
const [
|
const [
|
||||||
holdPaint,
|
holdPaint,
|
||||||
showMvmCtrls,
|
showMvmCtrls,
|
||||||
|
easterEgg,
|
||||||
] = useSelector((state) => [
|
] = useSelector((state) => [
|
||||||
state.gui.holdPaint,
|
state.gui.holdPaint,
|
||||||
state.gui.showMvmCtrls,
|
state.gui.showMvmCtrls,
|
||||||
|
state.gui.easterEgg,
|
||||||
], shallowEqual);
|
], shallowEqual);
|
||||||
const dispatch = useDispatch();
|
const dispatch = useDispatch();
|
||||||
|
|
||||||
|
@ -34,7 +36,7 @@ const PencilButton = () => {
|
||||||
}
|
}
|
||||||
// eslint-disable-next-line no-fallthrough
|
// eslint-disable-next-line no-fallthrough
|
||||||
case HOLD_PAINT.HISTORY:
|
case HOLD_PAINT.HISTORY:
|
||||||
if (window.let_me_cheat) {
|
if (easterEgg) {
|
||||||
nextMode = HOLD_PAINT.OVERLAY;
|
nextMode = HOLD_PAINT.OVERLAY;
|
||||||
dispatch(notify(t`Overlay Pencil ON`));
|
dispatch(notify(t`Overlay Pencil ON`));
|
||||||
break;
|
break;
|
||||||
|
|
|
@ -21,6 +21,7 @@ import {
|
||||||
import {
|
import {
|
||||||
HOLD_PAINT,
|
HOLD_PAINT,
|
||||||
} from '../core/constants';
|
} from '../core/constants';
|
||||||
|
import templateLoader from '../ui/templateLoader';
|
||||||
|
|
||||||
class PixelPainterControls {
|
class PixelPainterControls {
|
||||||
store;
|
store;
|
||||||
|
@ -413,6 +414,13 @@ class PixelPainterControls {
|
||||||
if (state.gui.holdPaint === HOLD_PAINT.HISTORY) {
|
if (state.gui.holdPaint === HOLD_PAINT.HISTORY) {
|
||||||
return renderer.getColorIndexOfPixel(...cell, true);
|
return renderer.getColorIndexOfPixel(...cell, true);
|
||||||
}
|
}
|
||||||
|
if (state.gui.holdPaint === HOLD_PAINT.OVERLAY) {
|
||||||
|
const rgb = templateLoader.getColorOfPixel(...cell);
|
||||||
|
if (!rgb) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
return state.canvas.palette.getIndexOfColor(...rgb);
|
||||||
|
}
|
||||||
return state.canvas.selectedColor;
|
return state.canvas.selectedColor;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -17,10 +17,13 @@ import {
|
||||||
setMoveV,
|
setMoveV,
|
||||||
setMoveW,
|
setMoveW,
|
||||||
} from '../store/actions';
|
} from '../store/actions';
|
||||||
|
import {
|
||||||
|
toggleOVEnabled,
|
||||||
|
} from '../store/actions/templates';
|
||||||
import { HOLD_PAINT } from '../core/constants';
|
import { HOLD_PAINT } from '../core/constants';
|
||||||
import { notify } from '../store/actions/thunks';
|
import { notify } from '../store/actions/thunks';
|
||||||
|
|
||||||
const charKeys = ['g', 'h', 'x', 'm', 'r', 'z', '+', '-'];
|
const charKeys = ['g', 'h', 'x', 'm', 't', 'r', 'z', '+', '-'];
|
||||||
|
|
||||||
export function createKeyUpHandler(store) {
|
export function createKeyUpHandler(store) {
|
||||||
return (event) => {
|
return (event) => {
|
||||||
|
@ -149,7 +152,10 @@ export function createKeyDownHandler(store) {
|
||||||
}
|
}
|
||||||
if (event.location === KeyboardEvent.DOM_KEY_LOCATION_RIGHT) {
|
if (event.location === KeyboardEvent.DOM_KEY_LOCATION_RIGHT) {
|
||||||
// right shift
|
// right shift
|
||||||
store.dispatch(selectHoldPaint(HOLD_PAINT.HISTORY, true));
|
store.dispatch(selectHoldPaint(
|
||||||
|
(store.getState().gui.easterEgg) ? HOLD_PAINT.OVERLAY : HOLD_PAINT.HISTORY,
|
||||||
|
true,
|
||||||
|
));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
|
@ -204,6 +210,13 @@ export function createKeyDownHandler(store) {
|
||||||
store.dispatch(notify(t`Copied!`));
|
store.dispatch(notify(t`Copied!`));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
case 't': {
|
||||||
|
store.dispatch(toggleOVEnabled());
|
||||||
|
store.dispatch(notify((store.getState().templates.ovEnabled)
|
||||||
|
? t`Overlay ON`
|
||||||
|
: t`Overlay OFF`));
|
||||||
|
return;
|
||||||
|
}
|
||||||
case 'z':
|
case 'z':
|
||||||
store.dispatch(toggleEasterEgg());
|
store.dispatch(toggleEasterEgg());
|
||||||
store.dispatch(notify((store.getState().gui.easterEgg)
|
store.dispatch(notify((store.getState().gui.easterEgg)
|
||||||
|
|
|
@ -696,7 +696,7 @@ export function bufferToBase64(array) {
|
||||||
|
|
||||||
reader.onload = (event) => {
|
reader.onload = (event) => {
|
||||||
const dataUrl = event.target.result;
|
const dataUrl = event.target.result;
|
||||||
const [_, base64] = dataUrl.split(',');
|
const [, base64] = dataUrl.split(',');
|
||||||
|
|
||||||
resolve(base64);
|
resolve(base64);
|
||||||
};
|
};
|
||||||
|
|
|
@ -15,7 +15,7 @@ export function listTemplate(imageId, title, canvasId, x, y, width, height) {
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
export function templatesReady(title) {
|
export function templatesReady() {
|
||||||
return {
|
return {
|
||||||
type: 'TEMPLATES_READY',
|
type: 'TEMPLATES_READY',
|
||||||
};
|
};
|
||||||
|
@ -36,8 +36,32 @@ export function changeTemplate(title, props) {
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function toggleOVEnabled() {
|
||||||
|
return {
|
||||||
|
type: 's/TGL_OVENABLED',
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
export function toggleSmallPxls() {
|
||||||
|
return {
|
||||||
|
type: 's/TGL_SMALLPXLS',
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
export function setOvOpacity(opacity) {
|
||||||
|
return {
|
||||||
|
type: 's/SET_O_OPACITY',
|
||||||
|
opacity,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
export function receivedTemplate() {
|
||||||
|
return {
|
||||||
|
type: 'REC_TEMPLATE',
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
export function updatedTemplateImage(imageId, width, height) {
|
export function updatedTemplateImage(imageId, width, height) {
|
||||||
console.log('update', width, height, 'store');
|
|
||||||
return {
|
return {
|
||||||
type: 's/UPD_TEMPLATE_IMG',
|
type: 's/UPD_TEMPLATE_IMG',
|
||||||
imageId,
|
imageId,
|
||||||
|
|
|
@ -105,6 +105,13 @@ export default (store) => (next) => (action) => {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
case 's/CHG_TEMPLATE':
|
||||||
|
case 's/TGL_OVENABLED':
|
||||||
|
case 's/TGL_SMALLPXLS':
|
||||||
|
case 's/REM_TEMPLATE':
|
||||||
|
case 's/UPD_TEMPLATE_IMG':
|
||||||
|
case 's/SET_O_OPACITY':
|
||||||
|
//
|
||||||
case 'REQ_BIG_CHUNK':
|
case 'REQ_BIG_CHUNK':
|
||||||
case 'PRE_LOADED_BIG_CHUNK':
|
case 'PRE_LOADED_BIG_CHUNK':
|
||||||
case 'REC_BIG_CHUNK':
|
case 'REC_BIG_CHUNK':
|
||||||
|
|
|
@ -7,7 +7,7 @@ const initialState = {
|
||||||
// prefix o: overlay, m: minimap
|
// prefix o: overlay, m: minimap
|
||||||
ovEnabled: false,
|
ovEnabled: false,
|
||||||
mEnabled: false,
|
mEnabled: false,
|
||||||
oOpacity: 1.0,
|
oOpacity: 70,
|
||||||
oSmallPxls: false,
|
oSmallPxls: false,
|
||||||
/*
|
/*
|
||||||
* [{
|
* [{
|
||||||
|
@ -100,6 +100,24 @@ export default function templates(
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
case 's/TGL_OVENABLED':
|
||||||
|
return {
|
||||||
|
...state,
|
||||||
|
ovEnabled: !state.ovEnabled,
|
||||||
|
};
|
||||||
|
|
||||||
|
case 's/TGL_SMALLPXLS':
|
||||||
|
return {
|
||||||
|
...state,
|
||||||
|
oSmallPxls: !state.oSmallPxls,
|
||||||
|
};
|
||||||
|
|
||||||
|
case 's/SET_O_OPACITY':
|
||||||
|
return {
|
||||||
|
...state,
|
||||||
|
oOpacity: action.opacity,
|
||||||
|
};
|
||||||
|
|
||||||
case 'TEMPLATES_READY':
|
case 'TEMPLATES_READY':
|
||||||
return {
|
return {
|
||||||
...state,
|
...state,
|
||||||
|
|
|
@ -422,8 +422,8 @@ class Renderer2D extends Renderer {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
context.restore();
|
context.restore();
|
||||||
// TODO conditions
|
|
||||||
if (false) {
|
if (state.templates.ovEnabled && !state.templates.oSmallPxls) {
|
||||||
renderOverlay(
|
renderOverlay(
|
||||||
state, this.canvas, chunkPosition, scale,
|
state, this.canvas, chunkPosition, scale,
|
||||||
this.tiledScale, this.scaleThreshold,
|
this.tiledScale, this.scaleThreshold,
|
||||||
|
@ -554,8 +554,9 @@ class Renderer2D extends Renderer {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO conditions
|
if (viewscale >= 5 && state.templates.ovEnabled
|
||||||
if (viewscale >= 5) {
|
&& state.templates.oSmallPxls
|
||||||
|
) {
|
||||||
renderSmallPOverlay(viewport, _view, viewscale);
|
renderSmallPOverlay(viewport, _view, viewscale);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -113,6 +113,7 @@ export function renderOverlay(
|
||||||
tiledScale,
|
tiledScale,
|
||||||
scaleThreshold,
|
scaleThreshold,
|
||||||
) {
|
) {
|
||||||
|
if (!templateLoader.ready) return;
|
||||||
const { canvasSize } = state.canvas;
|
const { canvasSize } = state.canvas;
|
||||||
// world coordinates of center of center chunk
|
// world coordinates of center of center chunk
|
||||||
const [x, y] = centerChunk
|
const [x, y] = centerChunk
|
||||||
|
@ -135,6 +136,7 @@ export function renderOverlay(
|
||||||
|
|
||||||
context.save();
|
context.save();
|
||||||
context.scale(offscreenScale, offscreenScale);
|
context.scale(offscreenScale, offscreenScale);
|
||||||
|
context.globalAlpha = state.templates.oOpacity / 100;
|
||||||
for (const template of templates) {
|
for (const template of templates) {
|
||||||
const image = templateLoader.getTemplateSync(template.imageId);
|
const image = templateLoader.getTemplateSync(template.imageId);
|
||||||
if (!image) continue;
|
if (!image) continue;
|
||||||
|
@ -156,6 +158,7 @@ export function renderSmallPOverlay(
|
||||||
view,
|
view,
|
||||||
scale,
|
scale,
|
||||||
) {
|
) {
|
||||||
|
if (!templateLoader.ready) return;
|
||||||
const [x, y] = view;
|
const [x, y] = view;
|
||||||
const { width, height } = $viewport;
|
const { width, height } = $viewport;
|
||||||
const horizontalRadius = width / 2 / scale;
|
const horizontalRadius = width / 2 / scale;
|
||||||
|
|
|
@ -9,6 +9,7 @@ import {
|
||||||
updatedTemplateImage,
|
updatedTemplateImage,
|
||||||
changeTemplate,
|
changeTemplate,
|
||||||
templatesReady,
|
templatesReady,
|
||||||
|
receivedTemplate,
|
||||||
} from '../store/actions/templates';
|
} from '../store/actions/templates';
|
||||||
import { bufferToBase64, base64ToBuffer } from '../core/utils';
|
import { bufferToBase64, base64ToBuffer } from '../core/utils';
|
||||||
import Template from './Template';
|
import Template from './Template';
|
||||||
|
@ -76,21 +77,39 @@ class TemplateLoader {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
getColorOfPixel(x, y) {
|
||||||
|
const templatesInView = this.#store.getState().templates.list
|
||||||
|
.filter((template) => (
|
||||||
|
template.enabled && template.x < x && template.y < y
|
||||||
|
&& template.x + template.width > x
|
||||||
|
&& template.y + template.height > y
|
||||||
|
));
|
||||||
|
|
||||||
|
for (const tData of templatesInView) {
|
||||||
|
const image = this.getTemplateSync(tData.imageId);
|
||||||
|
if (!image) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
const ctx = image.getContext('2d');
|
||||||
|
const rgb = ctx.getImageData(x - tData.x, y - tData.y, 1, 1).data;
|
||||||
|
if (rgb[3] > 200) {
|
||||||
|
return [rgb[0], rgb[1], rgb[2]];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
getTemplatesInView(x, y, horizontalRadius, verticalRadius) {
|
getTemplatesInView(x, y, horizontalRadius, verticalRadius) {
|
||||||
const topX = x - horizontalRadius;
|
const topX = x - horizontalRadius;
|
||||||
const topY = y - verticalRadius;
|
const topY = y - verticalRadius;
|
||||||
const bottomX = x + horizontalRadius;
|
const bottomX = x + horizontalRadius;
|
||||||
const bottomY = y + verticalRadius;
|
const bottomY = y + verticalRadius;
|
||||||
|
|
||||||
const templates = [];
|
return this.#store.getState().templates.list.filter((template) => (
|
||||||
this.#store.getState().templates.list.forEach((template) => {
|
template.enabled && template.x < bottomX && template.y < bottomY
|
||||||
if (x < bottomX && y < bottomY
|
&& template.x + template.width > topX
|
||||||
&& x + template.width > topX && y + template.height > topY
|
&& template.y + template.height > topY
|
||||||
) {
|
));
|
||||||
templates.push(template);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
return templates;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -141,6 +160,7 @@ class TemplateLoader {
|
||||||
const template = new Template(imageId);
|
const template = new Template(imageId);
|
||||||
await template.fromBuffer(buffer, mimetype);
|
await template.fromBuffer(buffer, mimetype);
|
||||||
this.#templates.set(imageId, template);
|
this.#templates.set(imageId, template);
|
||||||
|
this.#store.dispatch(receivedTemplate());
|
||||||
return template;
|
return template;
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
// eslint-disable-next-line no-console
|
// eslint-disable-next-line no-console
|
||||||
|
|
Loading…
Reference in New Issue
Block a user