Skip to content

Commit

Permalink
feature to highlight all/ink/paper manual pixels and all/bright attri…
Browse files Browse the repository at this point in the history
…butes
  • Loading branch information
arttu76 committed Dec 3, 2023
1 parent 4b4c31b commit 8935a7a
Show file tree
Hide file tree
Showing 7 changed files with 104 additions and 15 deletions.
40 changes: 30 additions & 10 deletions src/components/Screen.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,12 +6,12 @@ import { useAppDispatch, useAppSelector } from '../store/store';
import React from 'react';
import { repaint } from '../store/housekeepingSlice';
import { setLayerX, setLayerY } from "../store/layersSlice";
import { AttributeBrushType, Color, DragState, Keys, Layer, MaskBrushType, Nullable, PixelBrushType, PixelationType, Rgb, SpectrumPixelCoordinate, ToolType, Undefinable, XY } from "../types";
import { AttributeBrushType, Color, DragState, HighlightType, Keys, Layer, MaskBrushType, Nullable, PixelBrushType, PixelationType, Rgb, SpectrumPixelCoordinate, ToolType, Undefinable, XY } from "../types";
import { spectrumColor } from '../utils/colors';
import { getGrowableGridData, setGrowableGridData } from '../utils/growableGridManager';
import { isMaskSet, setMask } from '../utils/maskManager';
import { drawSpectrumMemoryToImageDatas, getDefaultColor, getInvertedAttributes, getInvertedBitmap, getSpectrumMemoryAttribute, getSpectrumMemoryAttributeByte, setSpectrumMemoryAttribute, setSpectrumMemoryPixel } from '../utils/spectrumHardware';
import { addAttributeGridUi, addMaskUiToLayer, addMouseCursor, getBackgroundValue, getCoordinatesCoveredByCursor, getCoordinatesCoveredByCursorInSourceImageCoordinates, replaceEmptyWithBackground } from '../utils/uiPixelOperations';
import { addAttributeGridUi, addMaskUiToLayer, addMouseCursor, getBackgroundValue, getCoordinatesCoveredByCursor, getCoordinatesCoveredByCursorInSourceImageCoordinates, getMaskColor, replaceEmptyWithBackground } from '../utils/uiPixelOperations';
import { applyRange2DExclusive, clamp8Bit, getInitialized2DArray, getWindow } from "../utils/utils";
import { Icon } from './Icon';

Expand Down Expand Up @@ -93,6 +93,8 @@ export const Screen = () => {
let topmostAdjustedPixel: Nullable<Rgb> = null;
let renderedPixel: Nullable<Rgb> = null;

let highlightMatch = false;

// loop visible layers from top to bottom
for (const layer of shownLayers) {

Expand All @@ -103,6 +105,27 @@ export const Screen = () => {
continue;
}

if (
tools.highlight !== HighlightType.none
&& layer.id === activeLayer?.id
) {
const highlightCheckedPixel = getGrowableGridData<boolean>(win[Keys.manualPixels]?.[layer.id], x, y);
if (highlightCheckedPixel !== null) {
highlightMatch = highlightMatch || (
tools.highlight === HighlightType.inkAndPaperPixels
|| (tools.highlight === HighlightType.inkPixels && highlightCheckedPixel === true)
|| (tools.highlight === HighlightType.paperPixels && highlightCheckedPixel === false)
);
}
const highlightCheckedAttribute = getGrowableGridData<Color>(win[Keys.manualAttributes]?.[layer.id], Math.floor(x / 8), Math.floor(y / 8));
if (highlightCheckedAttribute != null) {
highlightMatch = highlightMatch || (
tools.highlight === HighlightType.allAttributes
|| (tools.highlight === HighlightType.brightAttributes && highlightCheckedAttribute.bright)
);
}
}

let topmostAdjustedPixelFromThisLayer = false

const pixelIsUnmasked = tools.tool === ToolType.mask || !isMaskSet(layer, x, y, true);
Expand Down Expand Up @@ -203,14 +226,11 @@ export const Screen = () => {
? spectrumColor.bright
: spectrumColor.normal;

renderedPixel = pixel
? normalOrBrightColors[attribute.ink]
: normalOrBrightColors[attribute.paper]

setSpectrumMemoryPixel(win[Keys.spectrumMemoryBitmap], x, y, !!pixel);
if (x % 8 === 0 && y % 8 === 0) {
setSpectrumMemoryAttribute(win[Keys.spectrumMemoryAttribute], x, y, attribute);
}
renderedPixel = highlightMatch
? getMaskColor()
: pixel
? normalOrBrightColors[attribute.ink]
: normalOrBrightColors[attribute.paper]
}

if (!renderedPixel) {
Expand Down
37 changes: 34 additions & 3 deletions src/components/Toolbar.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ import {
setHideManualAttributes,
setHideManualPixels,
setHideSourceImage,
setHighlight,
setInvertExportedImage,
setManualAttribute,
setMaskBrushType,
Expand All @@ -31,7 +32,7 @@ import {
setZoom,
showHelp
} from "../store/toolsSlice";
import { AttributeBrushType, BrushShape, Color, Keys, MaskBrushType, Nullable, PixelBrushType, PixelationType, SpectrumPixelCoordinate, ToolType } from "../types";
import { AttributeBrushType, BrushShape, Color, HighlightType, Keys, MaskBrushType, Nullable, PixelBrushType, PixelationType, SpectrumPixelCoordinate, ToolType } from "../types";
import { isMaskSet, mutateMask } from '../utils/maskManager';
import { getInvertedAttributes, getInvertedBitmap, getSpectrumMemoryPixelOffsetAndBit, getTapeSoundAudioBufferSourceNode } from '../utils/spectrumHardware';
import { applyRange2DExclusive, getWindow, rangeExclusive, showAlert } from '../utils/utils';
Expand Down Expand Up @@ -770,8 +771,7 @@ export const Toolbar = () => {
icon="invert_colors_off"
tooltip={tools.hideAllAttributes ? 'All attributes are ink:0 paper:7 bright:0 (x)' : 'Using attributes (x)'}
onClick={() => dispatch(setHideAllAttributes(!tools.hideAllAttributes))} />
</Group>
<Group title="Display" disableClose={true}>
&nbsp;
<Input
tooltip="Attribute grid visibility (v)"
style={{ width: "50px", position: 'relative', top: '-2px', color: 'white' }}
Expand All @@ -786,6 +786,37 @@ export const Toolbar = () => {
icon={tools.crisp ? 'blur_off' : 'blur_on'}
tooltip={tools.crisp ? 'Crisp scaling' : 'Blurry scaling'}
onClick={() => dispatch(setCrispScaling(!tools.crisp))} />
{tools.tool === ToolType.pixels && <>
&nbsp;
<Button
icon="image"
dimmed={tools.highlight !== HighlightType.inkAndPaperPixels}
tooltip="Highlight all manually set pixels (ink or paper)"
onClick={() => dispatch(setHighlight(HighlightType.inkAndPaperPixels))} />
<Button
icon="gradient"
dimmed={tools.highlight !== HighlightType.inkPixels}
tooltip="Highlight all manually set ink pixels"
onClick={() => dispatch(setHighlight(HighlightType.inkPixels))} />
<Button
icon="palette"
dimmed={tools.highlight !== HighlightType.paperPixels}
tooltip="Highlight all manually set paper pixels"
onClick={() => dispatch(setHighlight(HighlightType.paperPixels))} />
</>}
{tools.tool === ToolType.attributes && <>
&nbsp;
<Button
icon="palette"
dimmed={tools.highlight !== HighlightType.allAttributes}
tooltip="Highlight all manually set attributes"
onClick={() => dispatch(setHighlight(HighlightType.allAttributes))} />
<Button
icon="light_mode"
dimmed={tools.highlight !== HighlightType.brightAttributes}
tooltip="Highlight all manually set bright attributes"
onClick={() => dispatch(setHighlight(HighlightType.brightAttributes))} />
</>}
</Group>
</>}

Expand Down
18 changes: 18 additions & 0 deletions src/store/highlightAutoDisablerMiddleware.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
import { AnyAction, Dispatch, MiddlewareAPI } from '@reduxjs/toolkit';
import { HighlightType } from '../types';
import { setHighlight } from './toolsSlice';

const highlightAutoDisablerMiddleware = (storeApi: MiddlewareAPI<Dispatch<AnyAction>>) => (next: Dispatch<AnyAction>) => (action: AnyAction) => {
if (
action.type === setHighlight.type
&& action.payload !== HighlightType.none
) {
setTimeout(
() => storeApi.dispatch(setHighlight(HighlightType.none)),
1000
);
}
return next(action);
};

export default highlightAutoDisablerMiddleware;
2 changes: 2 additions & 0 deletions src/store/store.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import { repaint as repaintAction } from './housekeepingSlice';

import { TypedUseSelectorHook, useDispatch, useSelector } from "react-redux";
import { restoreStateImageMaskPixelAttributeDataFromLocalStorage } from "../utils/exportImport";
import highlightAutoDisablerMiddleware from "./highlightAutoDisablerMiddleware";
import windowPropertyMiddleware from "./windowPropertyMiddleware";

const preloadedState = restoreStateImageMaskPixelAttributeDataFromLocalStorage();
Expand All @@ -27,6 +28,7 @@ const store = configureStore({
})
.concat(localStorageMiddleware)
.concat(windowPropertyMiddleware)
.concat(highlightAutoDisablerMiddleware)
});

export type RootState = ReturnType<typeof store.getState>
Expand Down
9 changes: 7 additions & 2 deletions src/store/toolsSlice.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import {
PayloadAction,
createSlice,
} from "@reduxjs/toolkit";
import { AttributeBrushType, BrushShape, Color, MaskBrushType, PixelBrushType, ToolType, ToolsSliceState } from "../types";
import { AttributeBrushType, BrushShape, Color, HighlightType, MaskBrushType, PixelBrushType, ToolType, ToolsSliceState } from "../types";

const initialState: ToolsSliceState = {
tool: ToolType.nudge,
Expand Down Expand Up @@ -32,7 +32,8 @@ const initialState: ToolsSliceState = {
showHelp: false,
loadStartedAt: null,
loadCurrentAt: null,
pulseOffsetsForData: []
pulseOffsetsForData: [],
highlight: HighlightType.none
}

const toolsSlice = createSlice({
Expand Down Expand Up @@ -120,6 +121,9 @@ const toolsSlice = createSlice({
resetLoadOffset: (state) => {
state.loadStartedAt = null;
state.loadCurrentAt = null;
},
setHighlight: (state, action: PayloadAction<HighlightType>) => {
state.highlight = action.payload;
}
}
})
Expand Down Expand Up @@ -149,6 +153,7 @@ export const {
setPulseOffsetsForData,
increaseLoadOffset,
resetLoadOffset,
setHighlight

} = toolsSlice.actions;

Expand Down
11 changes: 11 additions & 0 deletions src/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -116,6 +116,15 @@ export enum PixelationSource {
autoColor = 'autoColor'
}

export enum HighlightType {
none = 'none',
inkAndPaperPixels = 'inkAndPaperPixels',
inkPixels = 'inkPixels',
paperPixels = 'paperPixels',
allAttributes = 'allAttributes',
brightAttributes = 'brightAttributes'
}

export interface PixelationPattern extends withId {
limit: number;
pattern: BitImage;
Expand Down Expand Up @@ -223,6 +232,8 @@ export interface ToolsSliceState {
loadStartedAt: Nullable<number>; // timestamp when export playback was started
loadCurrentAt: Nullable<number>; // timestamp for current time
pulseOffsetsForData: number[]; // 3rd item of this array tells how many ticks have passed for previous bytes

highlight: HighlightType;
}

export interface State {
Expand Down
2 changes: 2 additions & 0 deletions src/utils/uiPixelOperations.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@ import { applyRange2DExclusive, bias, dotProduct, getLayerXYFromScreenCoordinate

const maskColor: Rgb = [255, 75, 0];

export const getMaskColor = (): Rgb => maskColor;

export const getBackgroundValue = (x: number, y: number): number => {
return 128
+ Math.floor(((x / 8) + Math.floor((y / 8) % 2)) % 2) * 64
Expand Down

0 comments on commit 8935a7a

Please sign in to comment.