improve script area display of inputs that spend a taproot script path

This commit is contained in:
Craig Raw 2024-02-28 10:29:14 +02:00
parent 6d7f02227a
commit 0ed8c6af7c
6 changed files with 42 additions and 22 deletions

2
drongo

@ -1 +1 @@
Subproject commit d2621eb87d787433d4358fa18acc7e78c330bc86 Subproject commit 0e1766a7093480b484e8e9f25b2e5d1bc4977b12

View file

@ -12,7 +12,12 @@ import org.fxmisc.richtext.event.MouseOverTextEvent;
import org.fxmisc.richtext.model.TwoDimensional; import org.fxmisc.richtext.model.TwoDimensional;
import java.time.Duration; import java.time.Duration;
import java.util.Collection;
import java.util.List;
import java.util.stream.Collectors;
import java.util.stream.Stream;
import static com.sparrowwallet.drongo.protocol.ScriptType.*;
import static org.fxmisc.richtext.model.TwoDimensional.Bias.Backward; import static org.fxmisc.richtext.model.TwoDimensional.Bias.Backward;
public abstract class BaseController { public abstract class BaseController {
@ -24,14 +29,11 @@ public abstract class BaseController {
scriptArea.setMouseOverTextDelay(Duration.ofMillis(150)); scriptArea.setMouseOverTextDelay(Duration.ofMillis(150));
scriptArea.addEventHandler(MouseOverTextEvent.MOUSE_OVER_TEXT_BEGIN, e -> { scriptArea.addEventHandler(MouseOverTextEvent.MOUSE_OVER_TEXT_BEGIN, e -> {
TwoDimensional.Position position = scriptArea.getParagraph(0).getStyleSpans().offsetToPosition(e.getCharacterIndex(), Backward); ScriptChunk hoverChunk = getScriptChunk(scriptArea, e.getCharacterIndex());
if(position.getMajor() % 2 == 0 && scriptArea.getScript().getChunks().size() > position.getMajor() / 2) { if(hoverChunk != null) {
ScriptChunk hoverChunk = scriptArea.getScript().getChunks().get(position.getMajor()/2); Point2D pos = e.getScreenPosition();
if(!hoverChunk.isOpCode()) { popupMsg.setText(describeScriptChunk(hoverChunk));
Point2D pos = e.getScreenPosition(); popup.show(scriptArea, pos.getX(), pos.getY() + 10);
popupMsg.setText(describeScriptChunk(hoverChunk));
popup.show(scriptArea, pos.getX(), pos.getY() + 10);
}
} }
}); });
scriptArea.addEventHandler(MouseOverTextEvent.MOUSE_OVER_TEXT_END, e -> { scriptArea.addEventHandler(MouseOverTextEvent.MOUSE_OVER_TEXT_END, e -> {
@ -80,4 +82,26 @@ public abstract class BaseController {
return "Invalid"; return "Invalid";
} }
public static ScriptChunk getScriptChunk(ScriptArea area, int characterIndex) {
TwoDimensional.Position position = area.getParagraph(0).getStyleSpans().offsetToPosition(characterIndex, Backward);
int ignoreCount = 0;
for(int i = 0; i < position.getMajor() && i < area.getParagraph(0).getStyleSpans().getSpanCount(); i++) {
Collection<String> styles = area.getParagraph(0).getStyleSpans().getStyleSpan(i).getStyle();
if(i < position.getMajor() && (styles.contains("") || styles.contains("script-nest"))) {
ignoreCount++;
}
}
boolean hashScripts = List.of(P2PKH, P2SH, P2WPKH, P2WSH).stream().anyMatch(type -> type.isScriptType(area.getScript()));
List<ScriptChunk> flatChunks = area.getScript().getChunks().stream().flatMap(chunk -> !hashScripts && chunk.isScript() ? chunk.getScript().getChunks().stream() : Stream.of(chunk)).collect(Collectors.toList());
int chunkIndex = position.getMajor() - ignoreCount;
if(chunkIndex < flatChunks.size()) {
ScriptChunk chunk = flatChunks.get(chunkIndex);
if(!chunk.isOpCode()) {
return chunk;
}
}
return null;
}
} }

View file

@ -58,6 +58,8 @@ public class ScriptArea extends CodeArea {
append("<signature" + signatureCount++ + ">", "script-signature"); append("<signature" + signatureCount++ + ">", "script-signature");
} else if(chunk.isPubKey()) { } else if(chunk.isPubKey()) {
append("<pubkey" + pubKeyCount++ + ">", "script-pubkey"); append("<pubkey" + pubKeyCount++ + ">", "script-pubkey");
} else if(chunk.isTaprootControlBlock()) {
append("<controlblock>", "script-controlblock");
} else if(chunk.isString()) { } else if(chunk.isString()) {
append(chunk.toString(), "script-other"); append(chunk.toString(), "script-other");
} else if(chunk.isScript()) { } else if(chunk.isScript()) {

View file

@ -2,25 +2,22 @@ package com.sparrowwallet.sparrow.control;
import com.sparrowwallet.drongo.protocol.Script; import com.sparrowwallet.drongo.protocol.Script;
import com.sparrowwallet.drongo.protocol.ScriptChunk; import com.sparrowwallet.drongo.protocol.ScriptChunk;
import com.sparrowwallet.sparrow.BaseController;
import javafx.geometry.Point2D; import javafx.geometry.Point2D;
import javafx.scene.control.ContextMenu; import javafx.scene.control.ContextMenu;
import javafx.scene.control.MenuItem; import javafx.scene.control.MenuItem;
import javafx.scene.input.Clipboard; import javafx.scene.input.Clipboard;
import javafx.scene.input.ClipboardContent; import javafx.scene.input.ClipboardContent;
import javafx.scene.input.ContextMenuEvent; import javafx.scene.input.ContextMenuEvent;
import org.fxmisc.richtext.CodeArea;
import org.fxmisc.richtext.model.TwoDimensional;
import java.util.OptionalInt; import java.util.OptionalInt;
import static org.fxmisc.richtext.model.TwoDimensional.Bias.Backward;
public class ScriptContextMenu extends ContextMenu { public class ScriptContextMenu extends ContextMenu {
private Script script; private Script script;
private MenuItem copyvalue; private MenuItem copyvalue;
private ScriptChunk hoverChunk; private ScriptChunk hoverChunk;
public ScriptContextMenu(CodeArea area, Script script) public ScriptContextMenu(ScriptArea area, Script script)
{ {
this.script = script; this.script = script;
@ -40,12 +37,9 @@ public class ScriptContextMenu extends ContextMenu {
Point2D point = area.screenToLocal(event.getScreenX(), event.getScreenY()); Point2D point = area.screenToLocal(event.getScreenX(), event.getScreenY());
OptionalInt characterIndex = area.hit(point.getX(), point.getY()).getCharacterIndex(); OptionalInt characterIndex = area.hit(point.getX(), point.getY()).getCharacterIndex();
if(characterIndex.isPresent()) { if(characterIndex.isPresent()) {
TwoDimensional.Position position = area.getParagraph(0).getStyleSpans().offsetToPosition(characterIndex.getAsInt(), Backward); ScriptChunk chunk = BaseController.getScriptChunk(area, characterIndex.getAsInt());
if(position.getMajor() % 2 == 0) { if(chunk != null) {
ScriptChunk chunk = script.getChunks().get(position.getMajor() / 2); this.hoverChunk = chunk;
if(!chunk.isOpCode()) {
this.hoverChunk = chunk;
}
} }
} }
copyvalue.setDisable(hoverChunk == null); copyvalue.setDisable(hoverChunk == null);

View file

@ -209,7 +209,7 @@ HorizontalHeaderColumn > TableColumnHeader.column-header.table-column{
.root .script-hash { -fx-fill: #d19a66 } .root .script-hash { -fx-fill: #d19a66 }
.root .script-signature { -fx-fill: #98c379 } .root .script-signature { -fx-fill: #98c379 }
.root .script-pubkey { -fx-fill: #c678dd } .root .script-pubkey { -fx-fill: #c678dd }
.root .script-redeem { -fx-fill: derive(#e06c75, 20%) } .root .script-redeem, .root .script-controlblock { -fx-fill: derive(#e06c75, 20%) }
.root .script-other { -fx-fill: #c8ccd4 } .root .script-other { -fx-fill: #c8ccd4 }
.root #txhex { .root #txhex {

View file

@ -3,7 +3,7 @@
.script-hash { -fx-fill: #986801 } .script-hash { -fx-fill: #986801 }
.script-signature { -fx-fill: #50a14f } .script-signature { -fx-fill: #50a14f }
.script-pubkey { -fx-fill: #a626a4 } .script-pubkey { -fx-fill: #a626a4 }
.script-redeem { -fx-fill: #ca1243 } .script-redeem, .script-controlblock { -fx-fill: #ca1243 }
.script-other { -fx-fill: #a0a1a7 } .script-other { -fx-fill: #a0a1a7 }
.non-final { .non-final {