-
Notifications
You must be signed in to change notification settings - Fork 62
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Shift + (Click/Arrows) in HexEditor to select multiple bytes #119
base: master
Are you sure you want to change the base?
Changes from 5 commits
082db12
8578958
076e69c
79a3057
3fe5762
c01f942
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
This file was deleted.
This file was deleted.
This file was deleted.
This file was deleted.
This file was deleted.
This file was deleted.
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -100,11 +100,10 @@ export class HexViewer { | |
private content: JQuery; | ||
private contentOuter: JQuery; | ||
|
||
public mouseDownOffset: number; | ||
private canDeselect: boolean; | ||
|
||
public selectionStart: number = -1; | ||
public selectionEnd: number = -1; | ||
public selectionCursor: number = -1; | ||
public onSelectionChanged: (() => void); | ||
|
||
private isRecursive: boolean; | ||
|
@@ -125,15 +124,18 @@ export class HexViewer { | |
if ("dataOffset" in cell) { | ||
if (e.type === "mousedown") { | ||
this.canDeselect = this.selectionStart === cell.dataOffset && this.selectionEnd === cell.dataOffset; | ||
this.mouseDownOffset = cell.dataOffset; | ||
this.content.on("mousemove", evt => this.cellMouseAction(evt)); | ||
this.setSelection(cell.dataOffset, cell.dataOffset); | ||
if (e.shiftKey) { | ||
this.shiftCursor(cell.dataOffset); | ||
} else { | ||
this.setCursor(cell.dataOffset); | ||
} | ||
} | ||
else if (e.type === "mousemove") { | ||
this.setSelection(this.mouseDownOffset, cell.dataOffset); | ||
this.shiftCursor(cell.dataOffset); | ||
this.canDeselect = false; | ||
} | ||
else if (e.type === "mouseup" && this.canDeselect && this.mouseDownOffset === cell.dataOffset) | ||
else if (e.type === "mouseup" && this.canDeselect && this.selectionStart === cell.dataOffset) | ||
this.deselect(); | ||
|
||
this.contentOuter.focus(); | ||
|
@@ -177,12 +179,12 @@ export class HexViewer { | |
e.key === "ArrowRight" ? 1 : e.key === "ArrowLeft" ? -1 : null; | ||
|
||
if (selDiff === null) return; | ||
|
||
var newSel = this.selectionStart + selDiff; | ||
if (newSel < 0) newSel = 0; | ||
else if (newSel >= this.dataProvider.length) newSel = this.dataProvider.length - 1; | ||
Comment on lines
-182
to
-183
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. These indispensable checks are removed without any compensation. As a result, when you try to seek before the beginning using the keyboard keys (place the cursor somewhere on the first line of the hex dump and then press the Up Key So please at least bring them back so that this new implementation isn't broken more that the existing one. To be fair, this adjustment apparently solves the problem with the keyboard, but a similar problem persists using the mouse (clicking on some invisible "byte" below the hex dump), though it's much smaller bug. Here's the capture: It would be nice if you could solve it as well, preferably by moving this check that you removed here to some place common for both keyboard and mouse interaction, for example the |
||
|
||
this.setSelection(newSel); | ||
var newSel = this.selectionCursor + selDiff; | ||
if (e.shiftKey) { | ||
this.shiftCursor(newSel); | ||
} else { | ||
this.setCursor(newSel); | ||
} | ||
return false; | ||
}); | ||
} | ||
|
@@ -256,17 +258,27 @@ export class HexViewer { | |
hexCell.cell.dataOffset = asciiCell.dataOffset = dataOffset; | ||
|
||
var isSelected = this.selectionStart <= dataOffset && dataOffset <= this.selectionEnd; | ||
$(hexCell.cell).toggleClass("selected", isSelected); | ||
$(asciiCell).toggleClass("selected", isSelected); | ||
var isCursor = dataOffset === this.selectionCursor; | ||
var targets = [hexCell.cell, asciiCell]; | ||
$(targets).toggleClass("selected", isSelected); | ||
$(targets).toggleClass("cursor", isCursor); | ||
|
||
var skipInt = 0; | ||
for (var level = 0; level < this.maxLevel; level++) { | ||
var int = intervals[intIdx + level]; | ||
var intIn = int && int.start <= dataOffset && dataOffset <= int.end; | ||
var intStart = intIn && int.start === dataOffset; | ||
var intEnd = intIn && int.end === dataOffset; | ||
hexCell.levels[level].className = `l${this.maxLevel - 1 - level} ${((intBaseIdx + intIdx) % 2 === 0) ? "even" : "odd"}` + | ||
(intIn ? ` m${level}` : "") + (intStart ? " start" : "") + (intEnd ? " end" : "") + (isSelected ? " selected" : ""); | ||
var classes = [ | ||
`l${this.maxLevel - 1 - level}`, | ||
`${((intBaseIdx + intIdx) % 2 === 0) ? "even" : "odd"}`, | ||
generalmimon marked this conversation as resolved.
Show resolved
Hide resolved
|
||
]; | ||
if(intIn) classes.push(`m${level}`); | ||
if(intStart) classes.push("start"); | ||
if(intEnd) classes.push("end"); | ||
if(isSelected) classes.push("selected"); | ||
if(isCursor) classes.push("cursor"); | ||
hexCell.levels[level].className = classes.join(" "); | ||
|
||
if (intEnd) | ||
skipInt++; | ||
|
@@ -291,16 +303,49 @@ export class HexViewer { | |
} | ||
|
||
public deselect() { | ||
this.setSelection(-1, -1); | ||
this.setCursor(-1); | ||
} | ||
|
||
public setSelection(start: number, end?: number) { | ||
public setCursor (cursor: number) { | ||
this.selectionCursor = cursor; | ||
this.setSelection( | ||
this.selectionCursor | ||
); | ||
} | ||
|
||
public shiftCursor (cursor: number) { | ||
var start = this.selectionStart; | ||
var end = this.selectionEnd; | ||
if (this.selectionCursor === end) { | ||
end = cursor; | ||
} else if (this.selectionCursor === start) { | ||
start = cursor; | ||
} | ||
this.selectionCursor = cursor; | ||
this.setSelection( | ||
Math.max(0, start), | ||
end | ||
); | ||
} | ||
Comment on lines
+309
to
+329
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Hopefully these methods won't be needed at all when you eliminate the |
||
|
||
public setSelection(start: number, end?: number, cursor?: number) { | ||
if (this.isRecursive) return; | ||
end = end || start; | ||
|
||
var oldStart = this.selectionStart, oldEnd = this.selectionEnd; | ||
this.selectionStart = start < end ? start : end; | ||
this.selectionEnd = Math.min(start < end ? end : start, this.dataProvider.length - 1); | ||
this.selectionStart = Math.min(start, end); | ||
this.selectionEnd = Math.min( | ||
Math.max(start, end), | ||
this.dataProvider.length - 1 | ||
); | ||
|
||
// is cursor out of bounds because called externally? | ||
if ( | ||
this.selectionCursor < this.selectionStart | ||
|| this.selectionCursor > this.selectionEnd | ||
) cursor = this.selectionEnd; | ||
if (cursor) this.selectionCursor = cursor; | ||
Comment on lines
+342
to
+347
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. A weird condition. I don't fully understand the case
Anyway, clamping feels weird when you consider that the situations above should never happen, because ideally In any case, this is the result of storing the |
||
|
||
if (this.selectionStart !== oldStart || this.selectionEnd !== oldEnd) { | ||
this.isRecursive = true; | ||
try { | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -207,15 +207,19 @@ class AppController { | |
|
||
onHexViewerSelectionChanged() { | ||
//console.log("setSelection", ui.hexViewer.selectionStart, ui.hexViewer.selectionEnd); | ||
localStorage.setItem("selection", JSON.stringify({ start: this.ui.hexViewer.selectionStart, end: this.ui.hexViewer.selectionEnd })); | ||
localStorage.setItem("selection", JSON.stringify({ | ||
start: this.ui.hexViewer.selectionStart, | ||
end: this.ui.hexViewer.selectionEnd, | ||
cursor: this.ui.hexViewer.selectionCursor | ||
})); | ||
|
||
var start = this.ui.hexViewer.selectionStart; | ||
var hasSelection = start !== -1; | ||
|
||
this.refreshSelectionInput(); | ||
|
||
if (this.ui.parsedDataTreeHandler && hasSelection && !this.selectedInTree) { | ||
var intervals = this.ui.parsedDataTreeHandler.intervalHandler.searchRange(this.ui.hexViewer.mouseDownOffset || start); | ||
var intervals = this.ui.parsedDataTreeHandler.intervalHandler.searchRange(this.ui.hexViewer.selectionCursor || start); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Makes perfect sense, thanks! 👍 One currently has to click on some byte using mouse in order to highlight the relevant field in the object tree, so indeed, the keyboard control of the Web IDE is quite limited. To be clear, I'm still convinced that |
||
if (intervals.items.length > 0) { | ||
//console.log("selected node", intervals[0].id); | ||
this.blockRecursive = true; | ||
|
@@ -281,7 +285,11 @@ $(() => { | |
app.inputReady.then(() => { | ||
var storedSelection = JSON.parse(localStorage.getItem("selection")); | ||
if (storedSelection) | ||
app.ui.hexViewer.setSelection(storedSelection.start, storedSelection.end); | ||
app.ui.hexViewer.setSelection( | ||
storedSelection.start, | ||
storedSelection.end, | ||
storedSelection.cursor | ||
); | ||
}); | ||
|
||
var editDelay = new Delayed(500); | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Again, I think that the special variable for
selectionCursor
is unnecessary, because always applies eitherselectionCursor == selectionStart
orselectionCursor == selectionEnd
, nothing between or outside. Why not introduce a single propertyisSelectionCursorAtEnd
which just distinguishes between these two states (instead of theselectionCursor
)?