Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 6 additions & 6 deletions app/frontend/static/css/canvas.css
Original file line number Diff line number Diff line change
Expand Up @@ -266,12 +266,12 @@
#save-canvas-png-btn:hover:not(:disabled) {
background-color: #0056b3;
}
#commit-masks-btn, #edit-save-btn{
#commit-masks-btn{
background-color: #28a745;
padding: 8px 16px;
font-size: 15px;
} /* Green for commit */
#commit-masks-btn:hover:not(:disabled), #edit-save-btn:hover:not(:disabled) {
#commit-masks-btn:hover:not(:disabled) {
background-color: #218838;
}
#edit-undo-btn, #edit-redo-btn {
Expand All @@ -282,7 +282,7 @@
}

/* Clear Inputs Button */
#clear-inputs-btn, #edit-cancel-btn {
#clear-inputs-btn, #edit-discard-btn {
background: linear-gradient(135deg, #ff7300, #ffa500);
border: none;
padding: 8px 16px;
Expand All @@ -293,20 +293,20 @@
transition: all 0.3s ease;
box-shadow: 0 2px 4px rgba(255, 140, 0, 0.2);
}
#clear-inputs-btn:hover:not(:disabled), #edit-cancel-btn:hover:not(:disabled) {
#clear-inputs-btn:hover:not(:disabled), #edit-discard-btn:hover:not(:disabled) {
background: linear-gradient(135deg, #e67e00, #cb7600);
box-shadow: 0 4px 8px rgba(255, 140, 0, 0.3);
transform: translateY(-1px);
}
#clear-inputs-btn:disabled, #edit-cancel-btn:disabled {
#clear-inputs-btn:disabled, #edit-discard-btn:disabled {
background: #ccc;
color: #888;
box-shadow: none;
transform: none;
cursor: not-allowed;
}

#clear-inputs-btn #edit-cancel-btn{
#clear-inputs-btn #edit-discard-btn{
width: 100%;
margin-top: 10px;
}
Expand Down
23 changes: 17 additions & 6 deletions app/frontend/static/js/canvasController.js
Original file line number Diff line number Diff line change
Expand Up @@ -521,7 +521,8 @@ class CanvasManager {
const color = (this.editingLayerId && l.layerId === this.editingLayerId)
? this.editingColor
: l.color;
if (mask) this._drawBinaryMask(mask, color, op);
const hatch = !(this.editingLayerId && l.layerId === this.editingLayerId);
if (mask) this._drawBinaryMask(mask, color, op, hatch);
});
}

Expand Down Expand Up @@ -737,6 +738,14 @@ class CanvasManager {

_handleWheel(e) {
if (!this.currentImage) return;

if (this.editingMask && e.ctrlKey) {
e.preventDefault();
const delta = e.deltaY < 0 ? 1 : -1;
this._dispatchEvent('brushSizeScroll', { delta });
return;
}

e.preventDefault();

const rect = this.userInputCanvas.getBoundingClientRect();
Expand Down Expand Up @@ -893,7 +902,7 @@ class CanvasManager {
}
}

_drawBinaryMask(maskData, colorStr, opacity = 1.0) {
_drawBinaryMask(maskData, colorStr, opacity = 1.0, hatch = true) {
if (!maskData || !maskData.length || !maskData[0].length) return;
const maskHeight = maskData.length;
const maskWidth = maskData[0].length;
Expand All @@ -909,7 +918,7 @@ class CanvasManager {
const [r, g, b, a_int] = this._parseRgbaFromString(colorStr);
const finalAlpha = Math.round(Math.min(1, Math.max(0, opacity)) * a_int);

const spacing = 6; // pixel spacing between hatch lines
const spacing = 4; // pixel spacing between hatch lines (tighter pattern)
const lineWidth = 2; // hatch line thickness

const isBorder = (mx, my) => {
Expand All @@ -926,7 +935,7 @@ class CanvasManager {
if (!maskData[y][x]) continue;
const idx = (y * maskWidth + x) * 4;
const border = isBorder(x, y);
const drawPixel = border || ((x + y) % spacing < lineWidth);
const drawPixel = border || !hatch || ((x + y) % spacing < lineWidth);
if (drawPixel) {
pixelData[idx] = r;
pixelData[idx + 1] = g;
Expand Down Expand Up @@ -1128,10 +1137,10 @@ class CanvasManager {
const cy = Math.round(y);
for (let j = -radius; j <= radius; j++) {
for (let i = -radius; i <= radius; i++) {
if (i*i + j*j <= radius*radius) {
if (i * i + j * j <= radius * radius) {
const nx = cx + i;
const ny = cy + j;
if (nx >=0 && ny >=0 && nx < w && ny < h) {
if (nx >= 0 && ny >= 0 && nx < w && ny < h) {
this.editingMask[ny][nx] = add ? 1 : 0;
}
}
Expand Down Expand Up @@ -1310,6 +1319,8 @@ class CanvasManager {
finishMaskEdit() {
this.editingLayerId = null;
this.editingMask = null;
this.editHistory = [];
this.editHistoryIndex = -1;
this.drawPredictionMaskLayer();
}

Expand Down
29 changes: 16 additions & 13 deletions app/frontend/static/js/editModeController.js
Original file line number Diff line number Diff line change
Expand Up @@ -33,8 +33,7 @@ class EditModeController {
this.invertBtn = document.getElementById('edit-invert-btn');
this.undoBtn = document.getElementById('edit-undo-btn');
this.redoBtn = document.getElementById('edit-redo-btn');
this.saveBtn = document.getElementById('edit-save-btn');
this.cancelBtn = document.getElementById('edit-cancel-btn');
this.discardBtn = document.getElementById('edit-discard-btn');
this.previewEl = document.getElementById('brush-preview');
}

Expand All @@ -51,8 +50,7 @@ class EditModeController {
if (this.invertBtn) this.invertBtn.addEventListener('click', () => this.actionInvert());
if (this.undoBtn) this.undoBtn.addEventListener('click', () => this.actionUndo());
if (this.redoBtn) this.redoBtn.addEventListener('click', () => this.actionRedo());
if (this.saveBtn) this.saveBtn.addEventListener('click', () => this.save());
if (this.cancelBtn) this.cancelBtn.addEventListener('click', () => this.cancel());
if (this.discardBtn) this.discardBtn.addEventListener('click', () => this.discard());
const canvas = this.canvasManager.userInputCanvas;
if (canvas) {
canvas.addEventListener('mousedown', (e) => this.onMouseDown(e));
Expand All @@ -62,6 +60,9 @@ class EditModeController {
canvas.addEventListener('contextmenu', (e) => e.preventDefault());
}
this.canvasManager.addEventListener('zoom-pan-changed', () => this.updatePreviewSize());
document.addEventListener('canvas-brushSizeScroll', (e) => {
this.adjustBrushSize(e.detail.delta);
});
}

updatePreviewSize() {
Expand All @@ -71,6 +72,15 @@ class EditModeController {
this.previewEl.style.height = `${r}px`;
}

adjustBrushSize(delta) {
this.brushSize += delta;
if (this.brushSize < 1) this.brushSize = 1;
const max = this.brushSizeInput ? parseInt(this.brushSizeInput.max, 10) : 50;
if (this.brushSize > max) this.brushSize = max;
if (this.brushSizeInput) this.brushSizeInput.value = this.brushSize;
this.updatePreviewSize();
}

beginEdit(layer) {
if (!layer) return;
this.activeLayer = layer;
Expand Down Expand Up @@ -188,15 +198,8 @@ class EditModeController {
this.canvasManager.redoEdit();
}

save() {
if (!this.activeLayer) return;
const edited = this.canvasManager.getEditedMask();
this.utils.dispatchCustomEvent('edit-save', { layerId: this.activeLayer.layerId, maskData: edited });
this.endEdit();
}

cancel() {
this.utils.dispatchCustomEvent('edit-cancel', {});
discard() {
this.utils.dispatchCustomEvent('edit-discard', {});
this.endEdit();
}
}
Expand Down
12 changes: 12 additions & 0 deletions app/frontend/static/js/layerViewController.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ class LayerViewController {
this.stateManager = stateManager;
this.layers = [];
this.selectedLayerIds = [];
this.lastSelectedLayerId = null;
this.allProjectTags = [];
this.tagifyInstances = {};
this.Utils = window.Utils || { dispatchCustomEvent: (n,d)=>document.dispatchEvent(new CustomEvent(n,{detail:d})) };
Expand Down Expand Up @@ -51,12 +52,14 @@ class LayerViewController {

setSelectedLayers(layerIds) {
this.selectedLayerIds = Array.isArray(layerIds) ? [...layerIds] : [];
this.lastSelectedLayerId = this.selectedLayerIds.length > 0 ? this.selectedLayerIds[this.selectedLayerIds.length - 1] : null;
this.render();
}

clearSelection() {
if (this.selectedLayerIds.length > 0) {
this.selectedLayerIds = [];
this.lastSelectedLayerId = null;
this.Utils.dispatchCustomEvent('layers-selected', { layerIds: [] });
this.render();
}
Expand All @@ -67,14 +70,20 @@ class LayerViewController {
const idx = this.selectedLayerIds.indexOf(layerId);
if (idx !== -1) {
this.selectedLayerIds.splice(idx, 1);
if (layerId === this.lastSelectedLayerId) {
this.lastSelectedLayerId = this.selectedLayerIds[this.selectedLayerIds.length - 1] || null;
}
} else {
this.selectedLayerIds.push(layerId);
this.lastSelectedLayerId = layerId;
}
} else {
if (this.selectedLayerIds.length === 1 && this.selectedLayerIds[0] === layerId) {
this.selectedLayerIds = [];
this.lastSelectedLayerId = null;
} else {
this.selectedLayerIds = [layerId];
this.lastSelectedLayerId = layerId;
}
}
this.Utils.dispatchCustomEvent('layers-selected', { layerIds: [...this.selectedLayerIds] });
Expand All @@ -88,6 +97,9 @@ class LayerViewController {
const selIdx = this.selectedLayerIds.indexOf(layerId);
if (selIdx !== -1) {
this.selectedLayerIds.splice(selIdx, 1);
if (layerId === this.lastSelectedLayerId) {
this.lastSelectedLayerId = this.selectedLayerIds[this.selectedLayerIds.length - 1] || null;
}
this.Utils.dispatchCustomEvent('layers-selected', { layerIds: [...this.selectedLayerIds] });
}
this.Utils.dispatchCustomEvent('layer-deleted', { layerId });
Expand Down
Loading