From be2555822065d94e5fc6600214106f25a741ec8d Mon Sep 17 00:00:00 2001 From: Anders Evenrud Date: Fri, 11 Oct 2019 21:52:57 +0200 Subject: [PATCH 1/5] Added ghost when dropping on iconview (#51) --- src/adapters/ui/iconview.js | 101 ++++++++++++++++++++++-------------- src/desktop.js | 2 +- src/styles/_iconview.scss | 5 ++ 3 files changed, 67 insertions(+), 41 deletions(-) diff --git a/src/adapters/ui/iconview.js b/src/adapters/ui/iconview.js index 81ed4df9..4d42a5c2 100644 --- a/src/adapters/ui/iconview.js +++ b/src/adapters/ui/iconview.js @@ -68,44 +68,58 @@ const view = (fileIcon, themeIcon, droppable) => (state, actions) => } else { onDropAction(actions)(ev, data, files); } - } + + actions.setGhost(false); + }, + + ondragleave: () => actions.setGhost(false), + ondragenter: () => actions.setGhost(true), + ondragover: ev => actions.setGhost(ev) }); } - }, state.entries.map((entry, index) => { - return h('div', { - class: 'osjs-desktop-iconview__entry' + ( - state.selected === index - ? ' osjs-desktop-iconview__entry--selected' - : '' - ), - oncontextmenu: ev => actions.openContextMenu({ev, entry, index}), - ontouchstart: ev => tapper(ev, () => actions.openEntry({ev, entry, index})), - ondblclick: ev => actions.openEntry({ev, entry, index}), - onclick: ev => actions.selectEntry({ev, entry, index}) - }, [ - h('div', { - class: 'osjs-desktop-iconview__entry__inner' + }, [ + ...state.entries.map((entry, index) => { + return h('div', { + class: 'osjs-desktop-iconview__entry' + ( + state.selected === index + ? ' osjs-desktop-iconview__entry--selected' + : '' + ), + oncontextmenu: ev => actions.openContextMenu({ev, entry, index}), + ontouchstart: ev => tapper(ev, () => actions.openEntry({ev, entry, index})), + ondblclick: ev => actions.openEntry({ev, entry, index}), + onclick: ev => actions.selectEntry({ev, entry, index}) }, [ h('div', { - class: 'osjs-desktop-iconview__entry__icon' + class: 'osjs-desktop-iconview__entry__inner' }, [ - h('img', { - src: entry.icon ? entry.icon : themeIcon(fileIcon(entry).name), - class: 'osjs-desktop-iconview__entry__icon__icon' - }), - entry.shortcut !== false - ? h('img', { - src: themeIcon('emblem-symbolic-link'), - class: 'osjs-desktop-iconview__entry__icon__shortcut' - }) - : null - ]), - h('div', { - class: 'osjs-desktop-iconview__entry__label' - }, entry.filename) - ]) - ]); - })); + h('div', { + class: 'osjs-desktop-iconview__entry__icon' + }, [ + h('img', { + src: entry.icon ? entry.icon : themeIcon(fileIcon(entry).name), + class: 'osjs-desktop-iconview__entry__icon__icon' + }), + entry.shortcut !== false + ? h('img', { + src: themeIcon('emblem-symbolic-link'), + class: 'osjs-desktop-iconview__entry__icon__shortcut' + }) + : null + ]), + h('div', { + class: 'osjs-desktop-iconview__entry__label' + }, entry.filename) + ]) + ]); + }), + h('div', { + class: 'osjs-desktop-iconview__entry osjs-desktop-iconview__entry--ghost', + style: { + display: state.ghost ? undefined : 'none' + } + }) + ]); const createShortcuts = (root, readfile, writefile) => { const read = () => { @@ -195,10 +209,10 @@ export class DesktopIconView extends EventEmitter { this.$root.style.right = `${rect.right}px`; } - _render(root) { + _render(settings) { const oldRoot = this.root; - if (root) { - this.root = root; + if (settings.path) { + this.root = settings.path; } if (this.$root) { @@ -206,14 +220,16 @@ export class DesktopIconView extends EventEmitter { this.iconview.reload(); } + this.iconview.toggleGrid(settings.grid); + return false; } return true; } - render(root) { - if (!this._render(root)) { + render(settings) { + if (!this._render(settings)) { return; } @@ -221,6 +237,7 @@ export class DesktopIconView extends EventEmitter { this.$root.className = 'osjs-desktop-iconview'; this.core.$root.appendChild(this.$root); + const root = settings.path; const {droppable} = this.core.make('osjs/dnd'); const {icon: fileIcon} = this.core.make('osjs/fs'); const {icon: themeIcon} = this.core.make('osjs/theme'); @@ -231,7 +248,8 @@ export class DesktopIconView extends EventEmitter { this.iconview = app({ selected: -1, - entries: [] + entries: [], + ghost: false }, { setEntries: entries => ({entries}), @@ -311,8 +329,11 @@ export class DesktopIconView extends EventEmitter { read() .then(entries => entries.filter(e => e.filename !== '..')) .then(entries => actions.setEntries(entries)); - } + }, + setGhost: ev => { + return {ghost: ev}; + } }, view(fileIcon, themeIcon, droppable), this.$root); this.iconview.reload(); diff --git a/src/desktop.js b/src/desktop.js index f183cb99..2320eca9 100644 --- a/src/desktop.js +++ b/src/desktop.js @@ -532,7 +532,7 @@ export default class Desktop extends EventEmitter { } if (settings.enabled) { - this.iconview.render(settings.path); + this.iconview.render(settings); this.iconview.resize(this.getRect()); } else { this.iconview.destroy(); diff --git a/src/styles/_iconview.scss b/src/styles/_iconview.scss index 4868b493..8a2b8a3d 100644 --- a/src/styles/_iconview.scss +++ b/src/styles/_iconview.scss @@ -88,6 +88,11 @@ text-overflow: ellipsis; } + &--ghost { + pointer-events: none; + background-color: rgba(255, 255, 255, 0.1); + } + &--selected { z-index: 1; overflow: visible; From f7c56c8c761eb94051bc994203e56bcb7eb86ba4 Mon Sep 17 00:00:00 2001 From: Anders Evenrud Date: Fri, 11 Oct 2019 23:28:08 +0200 Subject: [PATCH 2/5] Added emToPx utility function --- src/utils/dom.js | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/src/utils/dom.js b/src/utils/dom.js index 1650aff1..edcd264f 100644 --- a/src/utils/dom.js +++ b/src/utils/dom.js @@ -253,3 +253,18 @@ export const createNativeNotification = (options, onclick) => { return Promise.reject('Unsupported'); }; + +/** + * Calculates pixel size from em + * @param {number} em Em size + * @param {DOMElement} [root=document.body] Optional root element + * @return {number} Size in pixels + */ +export const emToPx = (em, root = document.body) => { + const px = parseInt( + getComputedStyle(root).fontSize, + 10 + ); + + return Math.round(px * em); +}; From 9359b4972b13a3257e50848e79bde73d83fa2f47 Mon Sep 17 00:00:00 2001 From: Anders Evenrud Date: Fri, 11 Oct 2019 23:28:31 +0200 Subject: [PATCH 3/5] Added initial support for grid-based desktop iconview (#51) --- src/adapters/ui/iconview.js | 156 +++++++++++++++++++++++++++++++++--- src/config.js | 3 +- 2 files changed, 149 insertions(+), 10 deletions(-) diff --git a/src/adapters/ui/iconview.js b/src/adapters/ui/iconview.js index 4d42a5c2..8a4e24e4 100644 --- a/src/adapters/ui/iconview.js +++ b/src/adapters/ui/iconview.js @@ -29,16 +29,39 @@ */ import {EventEmitter} from '@osjs/event-emitter'; import {h, app} from 'hyperapp'; +import {draggable, droppable} from '../../utils/dnd'; +import {emToPx} from '../../utils/dom'; import {doubleTap} from '../../utils/input'; import {pathJoin} from '../../utils/vfs'; const tapper = doubleTap(); +// +// FIXME: Excessive render on drop events +// + +// TODO: Needs real values +const ICON_WIDTH = 5.0; // ems +const ICON_HEIGHT = 6.5; // ems +const ICON_MARGIN = 0.5; // ems + const validVfsDrop = data => data && data.path; +const validInternalDrop = data => data && data.internal; + +// TODO: Use internal storage +const loadIconPositions = () => JSON.parse( + localStorage.getItem('___osjs_iconview_positions') || '[]' +); + +// TODO: Use internal storage +const saveIconPositions = positions => + localStorage.setItem('___osjs_iconview_positions', JSON.stringify(positions || [])); const onDropAction = actions => (ev, data, files, shortcut = true) => { if (validVfsDrop(data)) { - actions.addEntry({entry: data, shortcut}); + actions.addEntry({entry: data, shortcut, ev}); + } else if(validInternalDrop(data)) { + actions.moveEntry({entry: data.internal, ev}); } else if (files.length > 0) { actions.uploadEntries(files); } @@ -47,6 +70,67 @@ const onDropAction = actions => (ev, data, files, shortcut = true) => { const isRootElement = ev => ev.target && ev.target.classList.contains('osjs-desktop-iconview__wrapper'); +const calculateGridSizes = el => { + const {offsetWidth, offsetHeight} = el; + // TODO: Might cause reflow, do cache here + const sizeX = emToPx(ICON_WIDTH) + (emToPx(ICON_MARGIN) * 2); + const sizeY = emToPx(ICON_HEIGHT) + (emToPx(ICON_MARGIN) * 2); + const cols = Math.floor(offsetWidth / sizeX); + const rows = Math.floor(offsetHeight / sizeY); + return [rows, cols, sizeX, sizeY]; +}; + +const calculateIconPositions = (entries, positions, cols) => { + const savedPositions = entries.map(entry => { + const key = entry.shortcut === false ? entry.filename : entry.shortcut; + const found = positions.findIndex(s => s.key === key); + return found === -1 ? undefined : positions[found].position; + }); + + return entries.map((entry, index) => { + const x = index % cols; + const y = Math.floor(index / cols); + const _position = savedPositions[index] || [x, y]; + + return Object.assign(entry, {_position}); + }); +}; + +const isIconPositionBusy = (ev, {entries, grid: {sizeX, sizeY}}) => { + const col = Math.floor(ev.clientX / sizeX); + const row = Math.floor(ev.clientY / sizeY); + + return entries.findIndex(e => { + return e._position[0] === col && + e._position[1] === row; + }) !== -1; +}; + +const createIconStyle = (entry, index, {grid: {enabled, sizeX, sizeY}}) => { + const [left, top] = entry._position || [0, 0]; + + return enabled ? { + position: 'absolute', + top: String(top * sizeY) + 'px', + left: String(left * sizeX) + 'px' + } : {}; +}; + +const createGhostStyle = ({ghost, grid: {enabled, sizeX, sizeY}}) => { + const style = {}; + if (ghost instanceof Event) { + const col = Math.floor(ghost.clientX / sizeX); + const row = Math.floor(ghost.clientY / sizeY); + style.top = String(row * sizeY) + 'px'; + style.left = String(col * sizeX) + 'px'; + } + + return Object.assign({ + position: enabled ? 'absolute' : undefined, + display: ghost ? undefined : 'none' + }, style); +}; + const view = (fileIcon, themeIcon, droppable) => (state, actions) => h('div', { class: 'osjs-desktop-iconview__wrapper', @@ -80,6 +164,7 @@ const view = (fileIcon, themeIcon, droppable) => (state, actions) => }, [ ...state.entries.map((entry, index) => { return h('div', { + style: createIconStyle(entry, index, state), class: 'osjs-desktop-iconview__entry' + ( state.selected === index ? ' osjs-desktop-iconview__entry--selected' @@ -88,7 +173,12 @@ const view = (fileIcon, themeIcon, droppable) => (state, actions) => oncontextmenu: ev => actions.openContextMenu({ev, entry, index}), ontouchstart: ev => tapper(ev, () => actions.openEntry({ev, entry, index})), ondblclick: ev => actions.openEntry({ev, entry, index}), - onclick: ev => actions.selectEntry({ev, entry, index}) + onclick: ev => actions.selectEntry({ev, entry, index}), + oncreate: el => { + draggable(el, { + data: {internal: entry} + }); + } }, [ h('div', { class: 'osjs-desktop-iconview__entry__inner' @@ -115,9 +205,7 @@ const view = (fileIcon, themeIcon, droppable) => (state, actions) => }), h('div', { class: 'osjs-desktop-iconview__entry osjs-desktop-iconview__entry--ghost', - style: { - display: state.ghost ? undefined : 'none' - } + style: createGhostStyle(state) }) ]); @@ -207,6 +295,10 @@ export class DesktopIconView extends EventEmitter { this.$root.style.left = `${rect.left}px`; this.$root.style.bottom = `${rect.bottom}px`; this.$root.style.right = `${rect.right}px`; + + if (this.iconview) { + this.iconview.resize(); + } } _render(settings) { @@ -238,7 +330,6 @@ export class DesktopIconView extends EventEmitter { this.core.$root.appendChild(this.$root); const root = settings.path; - const {droppable} = this.core.make('osjs/dnd'); const {icon: fileIcon} = this.core.make('osjs/fs'); const {icon: themeIcon} = this.core.make('osjs/theme'); const {copy, readdir, readfile, writefile, unlink, mkdir} = this.core.make('osjs/vfs'); @@ -246,12 +337,24 @@ export class DesktopIconView extends EventEmitter { const shortcuts = createShortcuts(root, readfile, writefile); const read = readDesktopFolder(root, readdir, shortcuts); + const [rows, cols, sizeX, sizeY] = calculateGridSizes(this.$root); + this.iconview = app({ selected: -1, entries: [], - ghost: false + positions: loadIconPositions(), + ghost: false, + grid: { + enabled: settings.grid, + rows, + cols, + sizeX, + sizeY + } }, { - setEntries: entries => ({entries}), + setEntries: entries => state => { + return {entries: calculateIconPositions(entries, state.positions, state.grid.cols)}; + }, openDropContextMenu: ({ev, data, files}) => { this.createDropContextMenu(ev, data, files); @@ -292,7 +395,7 @@ export class DesktopIconView extends EventEmitter { // TODO }, - addEntry: ({entry, shortcut}) => (state, actions) => { + addEntry: ({entry, shortcut, ev}) => (state, actions) => { const dest = `${root}/${entry.filename}`; mkdir(root) @@ -325,12 +428,47 @@ export class DesktopIconView extends EventEmitter { return {selected: -1}; }, + moveEntry: ({entry, ev}) => (state) => { + if (!isIconPositionBusy(ev, state)) { + const positions = state.positions; + const key = entry.shortcut === false ? entry.filename : entry.shortcut; + const found = positions.findIndex(s => s.key === key); + const col = Math.floor(ev.clientX / sizeX); + const row = Math.floor(ev.clientY / sizeY); + const position = [col, row]; + const value = {key, position}; + + if (found !== -1) { + positions[found] = value; + } else { + positions.push(value); + } + + saveIconPositions(positions); + + return { + positions, + entries: calculateIconPositions(state.entries, positions, state.cols) + }; + } + return {}; + }, + reload: () => (state, actions) => { read() .then(entries => entries.filter(e => e.filename !== '..')) .then(entries => actions.setEntries(entries)); }, + resize: () => ({grid: {enabled}}) => { + const [rows, cols, sizeX, sizeY] = calculateGridSizes(this.$root); + return {grid: {enabled, rows, cols, sizeX, sizeY}}; + }, + + toggleGrid: enabled => ({grid}) => { + return {grid: Object.assign(grid, {enabled})}; + }, + setGhost: ev => { return {ghost: ev}; } diff --git a/src/config.js b/src/config.js index c5335b13..0613bc91 100644 --- a/src/config.js +++ b/src/config.js @@ -180,7 +180,8 @@ export const defaultConfiguration = { }, iconview: { enabled: false, - path: 'home:/.desktop' + path: 'home:/.desktop', + grid: true } } }, From 746d935c3635d16eb8f7c2f16428d7fedc0ae110 Mon Sep 17 00:00:00 2001 From: Anders Evenrud Date: Sat, 12 Oct 2019 21:03:05 +0200 Subject: [PATCH 4/5] Cleaned up grid handling in desktop iconview (#51) --- src/adapters/ui/iconview.js | 247 +++++++++++++++++++++--------------- 1 file changed, 146 insertions(+), 101 deletions(-) diff --git a/src/adapters/ui/iconview.js b/src/adapters/ui/iconview.js index 8a4e24e4..65687328 100644 --- a/src/adapters/ui/iconview.js +++ b/src/adapters/ui/iconview.js @@ -36,27 +36,12 @@ import {pathJoin} from '../../utils/vfs'; const tapper = doubleTap(); -// -// FIXME: Excessive render on drop events -// - -// TODO: Needs real values -const ICON_WIDTH = 5.0; // ems -const ICON_HEIGHT = 6.5; // ems -const ICON_MARGIN = 0.5; // ems - const validVfsDrop = data => data && data.path; const validInternalDrop = data => data && data.internal; -// TODO: Use internal storage -const loadIconPositions = () => JSON.parse( - localStorage.getItem('___osjs_iconview_positions') || '[]' -); - -// TODO: Use internal storage -const saveIconPositions = positions => - localStorage.setItem('___osjs_iconview_positions', JSON.stringify(positions || [])); - +/** + * Drop handler + */ const onDropAction = actions => (ev, data, files, shortcut = true) => { if (validVfsDrop(data)) { actions.addEntry({entry: data, shortcut, ev}); @@ -67,62 +52,34 @@ const onDropAction = actions => (ev, data, files, shortcut = true) => { } }; +/** + * Checks event is on a root element + */ const isRootElement = ev => ev.target && ev.target.classList.contains('osjs-desktop-iconview__wrapper'); -const calculateGridSizes = el => { - const {offsetWidth, offsetHeight} = el; - // TODO: Might cause reflow, do cache here - const sizeX = emToPx(ICON_WIDTH) + (emToPx(ICON_MARGIN) * 2); - const sizeY = emToPx(ICON_HEIGHT) + (emToPx(ICON_MARGIN) * 2); - const cols = Math.floor(offsetWidth / sizeX); - const rows = Math.floor(offsetHeight / sizeY); - return [rows, cols, sizeX, sizeY]; -}; - -const calculateIconPositions = (entries, positions, cols) => { - const savedPositions = entries.map(entry => { - const key = entry.shortcut === false ? entry.filename : entry.shortcut; - const found = positions.findIndex(s => s.key === key); - return found === -1 ? undefined : positions[found].position; - }); - - return entries.map((entry, index) => { - const x = index % cols; - const y = Math.floor(index / cols); - const _position = savedPositions[index] || [x, y]; - - return Object.assign(entry, {_position}); - }); -}; - -const isIconPositionBusy = (ev, {entries, grid: {sizeX, sizeY}}) => { - const col = Math.floor(ev.clientX / sizeX); - const row = Math.floor(ev.clientY / sizeY); - - return entries.findIndex(e => { - return e._position[0] === col && - e._position[1] === row; - }) !== -1; -}; - -const createIconStyle = (entry, index, {grid: {enabled, sizeX, sizeY}}) => { - const [left, top] = entry._position || [0, 0]; +/** + * Creates UI icon styles + */ +const createIconStyle = (entry, grid, enabled) => { + const [left, top] = grid.getPosition(entry._position || [0, 0]); return enabled ? { position: 'absolute', - top: String(top * sizeY) + 'px', - left: String(left * sizeX) + 'px' + top: String(top) + 'px', + left: String(left) + 'px' } : {}; }; -const createGhostStyle = ({ghost, grid: {enabled, sizeX, sizeY}}) => { +/** + * Creates UI drop ghost + */ +const createGhostStyle = (grid, ghost, enabled) => { const style = {}; if (ghost instanceof Event) { - const col = Math.floor(ghost.clientX / sizeX); - const row = Math.floor(ghost.clientY / sizeY); - style.top = String(row * sizeY) + 'px'; - style.left = String(col * sizeX) + 'px'; + const [col, row] = grid.getEventPosition(ghost); + style.top = row + 'px'; + style.left = col + 'px'; } return Object.assign({ @@ -131,7 +88,10 @@ const createGhostStyle = ({ghost, grid: {enabled, sizeX, sizeY}}) => { }, style); }; -const view = (fileIcon, themeIcon, droppable) => (state, actions) => +/** + * Creates UI view + */ +const view = (fileIcon, themeIcon, grid) => (state, actions) => h('div', { class: 'osjs-desktop-iconview__wrapper', oncontextmenu: ev => { @@ -164,7 +124,7 @@ const view = (fileIcon, themeIcon, droppable) => (state, actions) => }, [ ...state.entries.map((entry, index) => { return h('div', { - style: createIconStyle(entry, index, state), + style: createIconStyle(entry, grid, state.grid), class: 'osjs-desktop-iconview__entry' + ( state.selected === index ? ' osjs-desktop-iconview__entry--selected' @@ -205,10 +165,115 @@ const view = (fileIcon, themeIcon, droppable) => (state, actions) => }), h('div', { class: 'osjs-desktop-iconview__entry osjs-desktop-iconview__entry--ghost', - style: createGhostStyle(state) + style: createGhostStyle(grid, state.ghost, state.grid) }) ]); +/** + * Handles grid + * FIXME: Excessive render on drop events + */ +const createGrid = (root) => { + + // TODO: Needs real values + const ICON_WIDTH = 5.0; // ems + const ICON_HEIGHT = 6.5; // ems + const ICON_MARGIN = 0.5; // ems + + /* eslint-disable no-unused-vars */ + let rows = 0; + let cols = 0; + let sizeX = 0; + let sizeY = 0; + let positions = []; + + const resize = () => { + const {offsetWidth, offsetHeight} = root; + sizeX = emToPx(ICON_WIDTH) + (emToPx(ICON_MARGIN) * 2); + sizeY = emToPx(ICON_HEIGHT) + (emToPx(ICON_MARGIN) * 2); + cols = Math.floor(offsetWidth / sizeX); + rows = Math.floor(offsetHeight / sizeY); + }; + + const load = () => { + // TODO: Use internal storage + positions = JSON.parse( + localStorage.getItem( + '___osjs_iconview_positions' + ) || '[]' + ); + }; + + const save = () => { + // TODO: Use internal storage + return localStorage.setItem( + '___osjs_iconview_positions', + JSON.stringify(positions || []) + ); + }; + + const getOffset = ev => ([ + Math.floor(ev.clientX / sizeX), + Math.floor(ev.clientY / sizeY) + ]); + + const getPosition = ([left, top]) => ([ + left * sizeX, + top * sizeY + ]); + + const getEventPosition = ev => { + const [col, row] = getOffset(ev); + return [col * sizeX, row * sizeY]; + }; + + const isBusy = (ev, entries) => { + const [col, row] = getOffset(ev); + + return entries.findIndex(e => { + return e._position[0] === col && + e._position[1] === row; + }) !== -1; + }; + + const calculate = entries => { + const savedPositions = entries.map(entry => { + const key = entry.shortcut === false ? entry.filename : entry.shortcut; + const found = positions.findIndex(s => s.key === key); + return found === -1 ? undefined : positions[found].position; + }); + + return entries.map((entry, index) => { + const x = index % cols; + const y = Math.floor(index / cols); + const _position = savedPositions[index] || [x, y]; + + return Object.assign(entry, {_position}); + }); + }; + + const move = (ev, key) => { + const [col, row] = getOffset(ev); + const found = positions.findIndex(s => s.key === key); + + const position = [col, row]; + const value = {key, position}; + + if (found !== -1) { + positions[found] = value; + } else { + positions.push(value); + } + + return save(); + }; + + return {resize, load, save, calculate, move, isBusy, getPosition, getEventPosition}; +}; + +/** + * Handles shortcuts + */ const createShortcuts = (root, readfile, writefile) => { const read = () => { const filename = pathJoin(root, '.shortcuts.json'); @@ -240,6 +305,9 @@ const createShortcuts = (root, readfile, writefile) => { return {read, add, remove}; }; +/** + * Wrapper for handling reading the desktop folder + */ const readDesktopFolder = (root, readdir, shortcuts) => { const read = () => readdir(root, { showHiddenFiles: false @@ -336,25 +404,19 @@ export class DesktopIconView extends EventEmitter { const error = err => console.error(err); const shortcuts = createShortcuts(root, readfile, writefile); const read = readDesktopFolder(root, readdir, shortcuts); + const grid = createGrid(this.$root); - const [rows, cols, sizeX, sizeY] = calculateGridSizes(this.$root); + grid.load(); this.iconview = app({ selected: -1, entries: [], - positions: loadIconPositions(), ghost: false, - grid: { - enabled: settings.grid, - rows, - cols, - sizeX, - sizeY - } + grid: settings.grid }, { - setEntries: entries => state => { - return {entries: calculateIconPositions(entries, state.positions, state.grid.cols)}; - }, + setEntries: entries => state => ({ + entries: grid.calculate(entries) + }), openDropContextMenu: ({ev, data, files}) => { this.createDropContextMenu(ev, data, files); @@ -429,27 +491,11 @@ export class DesktopIconView extends EventEmitter { }, moveEntry: ({entry, ev}) => (state) => { - if (!isIconPositionBusy(ev, state)) { - const positions = state.positions; + if (!grid.isBusy(ev, state.entries)) { const key = entry.shortcut === false ? entry.filename : entry.shortcut; - const found = positions.findIndex(s => s.key === key); - const col = Math.floor(ev.clientX / sizeX); - const row = Math.floor(ev.clientY / sizeY); - const position = [col, row]; - const value = {key, position}; - - if (found !== -1) { - positions[found] = value; - } else { - positions.push(value); - } - - saveIconPositions(positions); + grid.move(ev, key); - return { - positions, - entries: calculateIconPositions(state.entries, positions, state.cols) - }; + return {entries: grid.calculate(state.entries)}; } return {}; }, @@ -460,9 +506,8 @@ export class DesktopIconView extends EventEmitter { .then(entries => actions.setEntries(entries)); }, - resize: () => ({grid: {enabled}}) => { - const [rows, cols, sizeX, sizeY] = calculateGridSizes(this.$root); - return {grid: {enabled, rows, cols, sizeX, sizeY}}; + resize: () => { + grid.resize(); }, toggleGrid: enabled => ({grid}) => { @@ -472,7 +517,7 @@ export class DesktopIconView extends EventEmitter { setGhost: ev => { return {ghost: ev}; } - }, view(fileIcon, themeIcon, droppable), this.$root); + }, view(fileIcon, themeIcon, grid), this.$root); this.iconview.reload(); } From 9ee4aa5e1d79a548a58e2148b6e6e40fcaf3d6b7 Mon Sep 17 00:00:00 2001 From: Anders Evenrud Date: Sat, 12 Oct 2019 21:10:10 +0200 Subject: [PATCH 5/5] Desktop icon creation can now handle grid positions (#51) --- src/adapters/ui/iconview.js | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/adapters/ui/iconview.js b/src/adapters/ui/iconview.js index 65687328..aeeffb95 100644 --- a/src/adapters/ui/iconview.js +++ b/src/adapters/ui/iconview.js @@ -288,7 +288,8 @@ const createShortcuts = (root, readfile, writefile) => { const contents = JSON.stringify(shortcuts || []); return writefile(filename, contents) - .catch(() => 0); + .then(() => shortcuts.length - 1) + .catch(() => -1); }; const add = entry => read(root) @@ -468,9 +469,11 @@ export class DesktopIconView extends EventEmitter { } return copy(entry, dest) + .then(() => grid.move(ev, entry.filename)) .then(() => actions.reload()) .catch(error); }) + .then(key => grid.move(ev, key)) .then(() => actions.reload()); return {selected: -1};