sel: allow both directions for multi-select (fix #893)
Signed-off-by: Varun Patil <radialapps@gmail.com>pull/953/head
parent
e69cee9dd4
commit
8c0f3dc8a2
|
@ -187,6 +187,7 @@ export default defineComponent({
|
||||||
touchScrollInterval: 0,
|
touchScrollInterval: 0,
|
||||||
touchScrollDelta: 0,
|
touchScrollDelta: 0,
|
||||||
touchMoveSelFrame: 0,
|
touchMoveSelFrame: 0,
|
||||||
|
multiSelectDelta: null as 1 | -1 | null,
|
||||||
}),
|
}),
|
||||||
|
|
||||||
mounted() {
|
mounted() {
|
||||||
|
@ -656,14 +657,19 @@ export default defineComponent({
|
||||||
const touchedDays = new Set<number>();
|
const touchedDays = new Set<number>();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Look behind for a selected photo.
|
* @brief Look behind/ahead for a selected photo.
|
||||||
* @returns the list of photos behind the current photo upto
|
* @param delta -1 for behind, 1 for ahead
|
||||||
* the first selected photo.
|
* @returns the list of photos behind/ahead the current photo upto
|
||||||
* @returns null if no selected photo is found.
|
* the first selected photo. Null if selected photo not found.
|
||||||
*/
|
*/
|
||||||
const lookBehind = (): IPhoto[] | undefined => {
|
const look = (delta: 1 | -1): IPhoto[] | undefined => {
|
||||||
const result: IPhoto[] = [];
|
const result: IPhoto[] = [];
|
||||||
for (let i = rowIdx; i >= Math.max(rowIdx - 1000, 0); i--) {
|
|
||||||
|
// Iterate all rows behind or ahead of this row
|
||||||
|
// A maximum of 1000 rows are checked in either direction
|
||||||
|
const i_s = rowIdx; // i-start
|
||||||
|
const i_e = delta < 0 ? Math.max(rowIdx - 1000, 0) : Math.min(rowIdx + 1000, rows.length); // i-end
|
||||||
|
for (let i = i_s; delta < 0 ? i >= i_e : i < i_e; i += delta) {
|
||||||
const row = rows[i];
|
const row = rows[i];
|
||||||
if (row.type !== 1) continue; // skip non-photo rows
|
if (row.type !== 1) continue; // skip non-photo rows
|
||||||
|
|
||||||
|
@ -671,8 +677,9 @@ export default defineComponent({
|
||||||
if (!row.photos?.length) break;
|
if (!row.photos?.length) break;
|
||||||
|
|
||||||
// Iterate photos in this row from the end
|
// Iterate photos in this row from the end
|
||||||
const sj = i === rowIdx ? pIdx : row.photos.length - 1;
|
const j_s = i === rowIdx ? pIdx : delta < 0 ? row.photos.length - 1 : 0; // j-start
|
||||||
for (let j = sj; j >= 0; j--) {
|
const j_e = delta < 0 ? 0 : row.photos.length; // j-end
|
||||||
|
for (let j = j_s; delta < 0 ? j >= j_e : j < j_e; j += delta) {
|
||||||
const p = row.photos[j];
|
const p = row.photos[j];
|
||||||
if (p.flag & this.c.FLAG_PLACEHOLDER || !p.fileid) continue;
|
if (p.flag & this.c.FLAG_PLACEHOLDER || !p.fileid) continue;
|
||||||
|
|
||||||
|
@ -686,7 +693,7 @@ export default defineComponent({
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
/** Select or de-select a photo and update touchedDays */
|
/**@brief Select or de-select a photo and update touchedDays */
|
||||||
const selfun = (p: IPhoto, val: boolean) => {
|
const selfun = (p: IPhoto, val: boolean) => {
|
||||||
this.selectPhoto(p, val, true);
|
this.selectPhoto(p, val, true);
|
||||||
touchedDays.add(p.dayid);
|
touchedDays.add(p.dayid);
|
||||||
|
@ -694,40 +701,56 @@ export default defineComponent({
|
||||||
const select = (p: IPhoto) => selfun(p, true);
|
const select = (p: IPhoto) => selfun(p, true);
|
||||||
const deselect = (p: IPhoto) => selfun(p, false);
|
const deselect = (p: IPhoto) => selfun(p, false);
|
||||||
|
|
||||||
// Select everything behind if found
|
/**
|
||||||
const behind = lookBehind();
|
* @brief Backtrack and select photos behind/ahead.
|
||||||
if (behind) {
|
* @param delta -1 for behind, 1 for ahead
|
||||||
|
* @returns true if did some actions
|
||||||
|
*/
|
||||||
|
const backtrack = (delta: 1 | -1): boolean => {
|
||||||
|
const list = look(delta);
|
||||||
|
if (!list) return false;
|
||||||
|
|
||||||
// Clear everything in front in this day
|
// Clear everything in front in this day
|
||||||
const detail = photo.d!.detail!;
|
const detail = photo.d!.detail!;
|
||||||
const pdIdx = detail.indexOf(photo);
|
const i_s = detail.indexOf(photo) - delta; // i-start
|
||||||
for (let i = pdIdx + 1; i < detail.length; i++) {
|
const i_e = delta < 0 ? detail.length : 0; // i-end
|
||||||
|
for (let i = i_s; delta < 0 ? i < i_e : i >= i_e; i -= delta) {
|
||||||
if (detail[i].flag & this.c.FLAG_SELECTED) {
|
if (detail[i].flag & this.c.FLAG_SELECTED) {
|
||||||
deselect(detail[i]);
|
deselect(detail[i]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// De-select everything else in front (other days)
|
// De-select everything else in front (other days)
|
||||||
|
// Note that reverse = ascending dayIds
|
||||||
for (const [_, p] of this.selection) {
|
for (const [_, p] of this.selection) {
|
||||||
if (this.isreverse ? p.dayid > photo.dayid : p.dayid < photo.dayid) {
|
// reverse XNOR behind => direction
|
||||||
|
if (this.isreverse === delta < 0 ? p.dayid > photo.dayid : p.dayid < photo.dayid) {
|
||||||
deselect(p);
|
deselect(p);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Select everything behind upto the selected photo
|
// Select everything behind upto the selected photo
|
||||||
for (const p of behind) {
|
for (const p of list) {
|
||||||
select(p);
|
select(p);
|
||||||
}
|
}
|
||||||
} else {
|
|
||||||
// Always select the photo that was clicked
|
// Do subsequent actions in the same direction
|
||||||
select(photo);
|
this.multiSelectDelta = delta;
|
||||||
}
|
return true;
|
||||||
|
};
|
||||||
|
|
||||||
|
// Prefer to select photos behind, i.e. moving ahead
|
||||||
|
// If nothing behind is found, try ahead
|
||||||
|
// Fall back to select the photo that was clicked
|
||||||
|
const delta = this.multiSelectDelta ?? -1;
|
||||||
|
backtrack(delta) || backtrack(-delta as typeof delta) || select(photo);
|
||||||
|
|
||||||
// Force update for all days that were touched
|
// Force update for all days that were touched
|
||||||
for (const dayid of touchedDays) {
|
for (const dayid of touchedDays) {
|
||||||
this.updateHeadSelected(this.heads.get(dayid)!);
|
this.updateHeadSelected(this.heads.get(dayid)!);
|
||||||
}
|
}
|
||||||
|
|
||||||
this.$forceUpdate();
|
this.$forceUpdate(); // set changes
|
||||||
},
|
},
|
||||||
|
|
||||||
/** Select or deselect all photos in a head */
|
/** Select or deselect all photos in a head */
|
||||||
|
|
Loading…
Reference in New Issue