Skip to content

Commit

Permalink
Add some common sense, fix some issues
Browse files Browse the repository at this point in the history
not at all done btw but just that much closer!!
  • Loading branch information
mrbuilder1961 committed Jan 21, 2025
1 parent 92035b3 commit a29a81a
Show file tree
Hide file tree
Showing 3 changed files with 82 additions and 73 deletions.
86 changes: 47 additions & 39 deletions src/main/java/obro1961/chatpatches/gui/ContextMenu.java
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,10 @@ public class ContextMenu {
static final Text UUID = Text.translatable("text.chatpatches.copy.uuid");
static final Text MENU_REPLY = Text.translatable("text.chatpatches.copy.reply");

// methods used for closing and initializing the menu
private static Consumer<Element> remove;
private static Consumer<ClickableWidget> addSelectableChild;

// widgets
/**
* The grid widget that contains all the buttons in this context menu.
Expand Down Expand Up @@ -127,7 +131,7 @@ public class ContextMenu {
* constructor}.
*/
public static final ContextMenu NO_OP = new ContextMenu(0, 0, NIL_HUD_LINE, List.of()) {
@Override public void init(Consumer<ClickableWidget> addSelectableChild) {}
@Override public void init() {}
@Override public void render(DrawContext drawContext, int mX, int mY, float delta) {}
@Override public void keyPressed(int keyCode, int scanCode, int modifiers) {}
@Override public boolean mouseClicked(double mX, double mY, int button) { return false; }
Expand All @@ -139,7 +143,7 @@ private ContextMenu(double mX, double mY, ChatHudLine hudLine, List<ChatHudLine.
this.gridData = new GridData(MAX_ROWS, MAX_COLUMNS);
this.buttonGrid = new GridWidget((int) mX, (int) mY);
this.selectedLine = hudLine;
this.selectedVisibles = selectedVisibles;
this.selectedVisibles = new ArrayList<>(selectedVisibles); //prepub get rid of this wrapper, we shouldnt need it if we add the noOp field

this.widgets = ((GridWidgetAccessor) buttonGrid).getChildren();

Expand All @@ -149,6 +153,15 @@ private ContextMenu(double mX, double mY, ChatHudLine hudLine, List<ChatHudLine.
: NIL_MSG_DATA.sender();
}

/**
* Ugly but critical method to grant the context menu access to ChatScreen methods.
* todo explain hopw this is critical and must be called before the context menu is used
*/
public static void updateHooks(Consumer<ClickableWidget> addSelectableChild, Consumer<Element> remove) {
ContextMenu.addSelectableChild = addSelectableChild;
ContextMenu.remove = remove;
}

/**
* Creates a new context menu with the specified Minecraft client
* and mouse position. If either mouse coordinate is negative, the
Expand All @@ -159,7 +172,7 @@ private ContextMenu(double mX, double mY, ChatHudLine hudLine, List<ChatHudLine.
* <p>This method effectively serves as a constructor and
* initializer for the context menu, as it populates the required
* fields. However, this shouldn't be confused with
* {@link #init(Consumer)}, which creates the widget buttons and
* {@link #init()}, which creates the widget buttons and
* related data structures.
*
* @apiNote Needed as a separate method from the constructor to
Expand All @@ -171,41 +184,22 @@ public static ContextMenu of(double mX, double mY) {
return NO_OP;

final List<ChatHudLine> chatMessages = ((ChatHudAccessor) mc.inGameHud.getChatHud()).chatpatches$getMessages();

// longer messages sometimes fail because extra spaces appear to be added,
// so it now uses startsWith() bc the first one never has extra spaces.
// (maybe still an issue, but I haven't had any problems lately)
String hMF = TextUtils.reorder( visibles.getFirst().content(), false );
String hoveredMessageFirst = hMF.isEmpty() ? "\n" : hMF; // fixes messages starting with newlines not being detected
String fH = TextUtils.reorder( visibles.getFirst().content(), false );
String firstHovered = fH.isEmpty() ? "\n" : fH; // fixes messages starting with newlines not being detected

// get hovered message index (messages) for all copying data
ChatHudLine selectedLine = chatMessages.stream()
.filter(msg -> Formatting.strip( msg.content().getString() ).startsWith(hoveredMessageFirst))
.filter(msg -> Formatting.strip( msg.content().getString() ).startsWith(firstHovered))
.findFirst()
.orElse(NIL_HUD_LINE);

// ensures the selected line is in ChatHud#messages
return chatMessages.contains(selectedLine) ? new ContextMenu(mX, mY, selectedLine, visibles) : NO_OP;
}

/**
* teehee!
*/
public static ContextMenu resize(ContextMenu oldMenu, int oldWidth, int oldHeight) {
if(oldMenu == NO_OP)
return NO_OP;

//prepub this doesnt work so figure it out, also see ChatScreenMixin#resizeContextMenu
// selectedvisibles seem to break even tho #of isnt called? but we put them in just fine so idk
int rescaledX = (int) (oldMenu.clickPos.x * mc.getWindow().getScaledWidth() / oldWidth);
int rescaledY = (int) (oldMenu.clickPos.y * mc.getWindow().getScaledHeight() / oldHeight);
ContextMenu resized = new ContextMenu(rescaledX, rescaledY, oldMenu.selectedLine, oldMenu.selectedVisibles);
ChatPatches.LOGGER.warn("{} old v, {} new v, equal? {}", oldMenu.selectedVisibles.size(), resized.selectedVisibles.size(),
oldMenu.selectedVisibles.equals(resized.selectedVisibles));
//resized.selectedVisibles.clear();
//resized.selectedVisibles.addAll(oldMenu.selectedVisibles);
return resized;
}


/**
* Registers a button in the {@linkplain #buttonGrid button grid} and
Expand Down Expand Up @@ -237,8 +231,8 @@ private void registerButton(@NotNull Text id, @NotNull Supplier<Text> tooltipCop

pressAction.onPress(b);

//todo idk why the menu doesnt close on click... see #mouseClicked
//dont close ourself bc then it closes the chat screen too
//fixme idk why the menu doesnt close on click... see #mouseClicked
close(); // close the menu after copying (fixme does this work?)
}).dimensions((int)clickPos.x, (int)clickPos.y, w, h).build();

button.setTooltip(Tooltip.of( tooltipCopyTextSupplier.get() )); //Text.of( tooltipCopyTextSupplier.get().getString().replaceAll("§", "&") )//prepub?
Expand Down Expand Up @@ -306,7 +300,12 @@ private void registerCopyOnlyButton(Text id, Text tooltipCopyText, int localRow,
/**
* todo...
*/
public void init(Consumer<ClickableWidget> addSelectableChild) {
public void init() {
if(addSelectableChild == null) {
ChatPatches.logReportMsg(new IllegalStateException("ChatScreen hook `addSelectableChild` not initialized"));
return;
}

// string buttons - unconditional
registerProxyButton(MENU_STRING, RAW_STR, 0, 0);
registerCopyOnlyButton(RAW_STR, selectedLine.content(), 0, 1);
Expand Down Expand Up @@ -347,7 +346,7 @@ else if(ce.getAction() == ClickEvent.Action.OPEN_URL && !webLinks.contains(ce.ge
}
return Optional.empty();
}, Style.EMPTY);
// todo: image not letting me click (no CE in style) and its not translatable, no idea whats wrong here but it cant work as of now
// fixme: image not letting me click (no CE in style) and its not translatable, no idea whats wrong here but it cant work as of now
ChatPatches.LOGGER.warn("[DEBUG] [ContextMenu] webLinks: {}, fileLinks: {} translatable: {}", webLinks, fileLinks, selectedLine.content().getContent() instanceof TranslatableTextContent ttc ?
ttc.getArgs() : "x");
if(!webLinks.isEmpty() || !fileLinks.isEmpty()) {
Expand Down Expand Up @@ -377,7 +376,7 @@ else if(ce.getAction() == ClickEvent.Action.OPEN_URL && !webLinks.contains(ce.ge
}, 0, 0);
}

buttonGrid.refreshPositions(); // todo do i have to manually change the dims of the grid menu?
buttonGrid.refreshPositions();
gridData.syncButtons();
widgets.forEach(w -> addSelectableChild.accept((ClickableWidget)w));
}
Expand All @@ -402,6 +401,9 @@ public void render(DrawContext drawContext, int mX, int mY, float delta) {
* in the chat, to indicate which message will be copied.
*/
private void renderSelectionOutline(DrawContext drawContext, int mX, int mY, float delta) {
if(selectedVisibles.isEmpty())
return;

ChatHud chatHud = mc.inGameHud.getChatHud();
ChatHudAccessor chat = (ChatHudAccessor) chatHud;
List<ChatHudLine.Visible> visibles = chat.chatpatches$getVisibleMessages();
Expand Down Expand Up @@ -439,7 +441,7 @@ private void renderMenuButtons(DrawContext drawContext, int mX, int mY, float de
//widgets.forEach(widget -> widget.forEachChild(clickableWidget -> clickableWidget.render(drawContext, mX, mY, delta)));

// alternative way to render widgets, but it's not recursive and takes advantage of ClickableWidget#forEachChild passing itself
widgets.forEach(widget -> ((ClickableWidget)widget).render(drawContext, mX, mY, delta));
widgets.forEach(w -> ((ClickableWidget)w).render(drawContext, mX, mY, delta));
}

public void keyPressed(int keyCode, int scanCode, int modifiers) {
Expand Down Expand Up @@ -512,17 +514,23 @@ public void mouseMoved(double mX, double mY) {

/**
* Unhooks all widgets provided by this context menu
* (originally from {@link #init(Consumer)}) from
* (originally from {@link #init()}) from
* the screen.
*
* @param remove The {@link Screen#remove(Element)}
* method, so that the widgets can be
* removed from the screen.
* @apiNote Uses {@link #remove}, aka the
* {@link Screen#remove(Element)} method, so
* the widgets can be removed from the
* screen properly.
*/
public void close(Consumer<Element> remove) {
public void close() {
if(remove == null) {
ChatPatches.logReportMsg(new IllegalStateException("ChatScreen hook `remove` not initialized"));
return;
}

buttonGrid.forEachChild(remove::accept);
//init();//prepub what is this?
//buttonGrid.forEachChild(addDrawableChild::accept);
//selectedVisibles.clear();
widgets.clear();
}

public boolean isMouseOver(double mX, double mY) {
Expand Down
62 changes: 32 additions & 30 deletions src/main/java/obro1961/chatpatches/mixin/gui/ChatScreenMixin.java
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,6 @@
import java.util.ArrayList;
import java.util.List;
import java.util.function.BiFunction;
import java.util.function.Consumer;
import java.util.regex.Pattern;
import java.util.regex.PatternSyntaxException;

Expand Down Expand Up @@ -100,7 +99,7 @@ public abstract class ChatScreenMixin extends Screen implements ChatScreenAccess
* Notably used to clear the message draft in
* {@link ScreenMixin#clearMessageDraft} to only do this when
* the user closes the ChatScreen; also in
* {@link ContextMenu#init(Consumer)} for the
* {@link ContextMenu#init()} for the
* {@code #MENU_REPLY} action.
*/
@Unique public void chatpatches$overrideChatText(String str) { chatField.setText(str); }
Expand All @@ -117,6 +116,8 @@ private void chatScreenInit(String originalChatText, CallbackInfo ci) {
else if(!originalChatText.equals("/"))
this.originalChatText = messageDraft;
}

ContextMenu.updateHooks(this::addSelectableChild, this::remove);
}

/**
Expand Down Expand Up @@ -229,9 +230,7 @@ private void renderSearchAndContextMenuStuff(DrawContext context, int mX, int mY

context.getMatrices().pop(); // stop shifting before the context menu renders so the chat field doesn't cut it off

// renders the context menu if the settings menu is not open
if(!isMouseOverSettingsMenu(mX, mY)) //todo does this make sense? what about `!showSettingsMenu`? experiment.
RenderUtils.profile("contextMenu", () -> contextMenu.render(context, mX, mY, delta));
RenderUtils.profile("contextMenu", () -> contextMenu.render(context, mX, mY, delta));

client.getProfiler().pop();
}
Expand All @@ -247,10 +246,6 @@ public boolean renderTooltipSmartly(DrawContext drawContext, TextRenderer textRe
return !isMouseOverSettingsMenu(mX, mY) && !contextMenu.isMouseOver(mX, mY);
}

@Inject(method = "resize", at = @At("HEAD"))
public void resizeContextMenu(MinecraftClient client, int width, int height, CallbackInfo ci) {
contextMenu = ContextMenu.resize(contextMenu, this.width, this.height); // screen dimension fields aren't updated yet, perfect for resizing!
}

/**
* Either resets or saves the drafts for the search and chat fields, depending on
Expand All @@ -267,7 +262,8 @@ public void onScreenClose(CallbackInfo ci) {
else if(!searchField.getText().isEmpty())
client.inGameHud.getChatHud().reset(); // reset the hud if it had anything in the field (#102)

contextMenu.close(this::remove);
contextMenu = ContextMenu.NO_OP; // not unhooking here, because the screen is totally gone so rendering/usage is impossible
ContextMenu.updateHooks(null, null);
}

/** Clears the message draft **AFTER** a message has been (successfully) sent. Uses At.Shift.AFTER to ensure we don't clear if an error occurs */
Expand Down Expand Up @@ -295,7 +291,7 @@ private boolean fixMenuClickthroughClick(ChatHud chatHud, double mX, double mY,
}

@WrapOperation(method = "mouseClicked", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/gui/screen/ChatScreen;getTextStyleAt(DD)Lnet/minecraft/text/Style;"))
private Style fixMenuClickthroughStyle(ChatScreen screen, double mX, double mY, Operation<Style> getTextStyleAt) {
private Style fixStyleClickthrough(ChatScreen screen, double mX, double mY, Operation<Style> getTextStyleAt) {
return (isMouseOverSettingsMenu(mX, mY) || contextMenu.isMouseOver(mX, mY))
? null
: getTextStyleAt.call(screen, mX, mY);
Expand Down Expand Up @@ -326,6 +322,8 @@ public void registerClickEvents(double mX, double mY, int button, CallbackInfoRe
if(cir.getReturnValue())
return;

boolean closeContextMenu = true;

if(searchField.mouseClicked(mX, mY, button))
cir.setReturnValue(true);

Expand All @@ -336,28 +334,32 @@ public void registerClickEvents(double mX, double mY, int button, CallbackInfoRe
cir.setReturnValue(true);
if(regexButton.mouseClicked(mX, mY, button))
cir.setReturnValue(true);
} else { // context menu (prepub: clarify what)
// todo: clicking on search bar w cm open moves selection box to the bottom, clicking on the buttons doesnt close the cm
// also todo: this can def (really? maybe...) be moved into a static ContextMenu method
if(button == GLFW.GLFW_MOUSE_BUTTON_RIGHT) {
ContextMenu mousePosMenu = ContextMenu.of(mX, mY);
// if the mouse right-clicked elsewhere and that location can load a context menu, use it
if(contextMenu.clickPos.x != mX || contextMenu.clickPos.y != mY && mousePosMenu != ContextMenu.NO_OP) {
contextMenu.close(this::remove); // unhook the old context menu buttons
contextMenu = mousePosMenu; // keep and use the updated context menu
contextMenu.init(this::addSelectableChild); // initialize the context menu and register the provided buttons
cir.setReturnValue(true);
}
} else { // if we're not initializing the context menu, then delegate back to it
//todo: mouse clicks are not registering
contextMenu.mouseClicked(mX, mY, button);

// close the menu because if it clicked it should close; otherwise it clicked off and should still close
} else if(button == GLFW.GLFW_MOUSE_BUTTON_LEFT || contextMenu.mouseClicked(mX, mY, button)) {
closeContextMenu = false;
contextMenu.close();
contextMenu = ContextMenu.NO_OP; // idk if we need to do this but... maybe? todo
cir.setReturnValue(true);
} else if(button == GLFW.GLFW_MOUSE_BUTTON_RIGHT) {
// fixme: figure out how to close menu if anything other than right-click or menu clicked
// prepub: move this into a static ContextMenu method

ContextMenu mousePosMenu = ContextMenu.of(mX, mY);
// if the mouse right-clicked elsewhere and that location can load a context menu, use it
if(contextMenu.clickPos.x != mX || contextMenu.clickPos.y != mY && mousePosMenu != ContextMenu.NO_OP) {
contextMenu.close(); // unhook the old context menu buttons
contextMenu = mousePosMenu; // keep and use the updated context menu
contextMenu.init(); // initialize the context menu and register the provided buttons
closeContextMenu = false;
cir.setReturnValue(true);
contextMenu.close(this::remove);
contextMenu = ContextMenu.NO_OP;
}
}

// if anything was clicked other than the context menu, and it was open, then close it
if(closeContextMenu && contextMenu != ContextMenu.NO_OP) {//fixme (mayb not this statement idk) outline still renders after closing menu... but instead of setting = noop, what if
// we just add a noOp field to contextmenu and when we close it, we set it to true, and effectively brick the entire context menu? seems easier and epic
contextMenu.close();
contextMenu = ContextMenu.NO_OP;
}
}

/**
Expand Down
7 changes: 3 additions & 4 deletions src/main/java/obro1961/chatpatches/util/ChatUtils.java
Original file line number Diff line number Diff line change
Expand Up @@ -149,7 +149,7 @@ public static MutableText buildMessage(@Nullable Style rootStyle, @Nullable Text
* @implNote
* <ol>
* <li>Return {@code m} early if the chat log is suspended to not cause
* other issues. Also, restructures the message if necessary.</li>
* other issues.</li>
* <li>Reconstruct the message if {@linkplain Config#chatName allowed},
* it has player message data, and is in the vanilla format as specified
* {@linkplain #VANILLA_FORMAT here}:
Expand Down Expand Up @@ -189,9 +189,8 @@ public static MutableText buildMessage(@Nullable Style rootStyle, @Nullable Text
* </ol>
*/
public static Text modifyMessage(@NotNull Text m) {
if(ChatLog.isSuspended()) // cancel modifications when loading the chat log
// restructure the message if it's not already formatted (fixme: should this be here?)
return m.getSiblings().size() != DUPE_INDEX ? buildMessage(m.getStyle(), null, m, null) : m;
if(ChatLog.isSuspended())
return m; // cancel modifications when loading the chat log

boolean lastEmpty = msgData.equals(ChatUtils.NIL_MSG_DATA);
Date now = lastEmpty ? new Date() : msgData.timestamp;
Expand Down

0 comments on commit a29a81a

Please sign in to comment.