Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
44 commits
Select commit Hold shift + click to select a range
7008dfb
Feat: Color Picker rewrite & alpha slider/presets
Superkat32 Jul 17, 2026
26e1172
Feat: Re-add Color Picker confirm/cancel buttons, allow color picker …
Superkat32 Jul 17, 2026
692b243
Feat: Improve color picker button scaling & precise preview alpha bac…
Superkat32 Jul 17, 2026
ef8955b
Feat: Better Color Picker cursor shenanigans
Superkat32 Jul 17, 2026
8bb3c44
Feat: Add color pickers to Sprite, Outline, Popup, and Text Block Pro…
Superkat32 Jul 17, 2026
b697309
Chore: Sweep sweep
Superkat32 Jul 17, 2026
e5878b0
Chore: Extra cleanup
Superkat32 Jul 17, 2026
18bf8f3
Feat: Add background color into main screen for Text Block
Superkat32 Jul 17, 2026
7edc7f9
Chore: Optimize imports for various classes updated in the Color Pick…
Superkat32 Jul 17, 2026
24b8029
Feat: Begin GlowcaseMultilineEditBox
Superkat32 Jul 28, 2026
dbe1656
Feat: Begin GlowcaseMultilineEditBox (but also include these in case …
Superkat32 Jul 28, 2026
c063be9
Feat: To-done: Multi-character selection (in Text Block screen) at th…
Superkat32 Jul 28, 2026
4735a2b
Feat: Some cleanup and comments, before I work on the note edit screen
Superkat32 Jul 28, 2026
ec6745e
Feat: Beginning of overflow editing within GlowcaseMultilineEditBox
Superkat32 Jul 30, 2026
ae81755
Feat: Better text overflow handling, break word selection/moving at tags
Superkat32 Aug 1, 2026
e16e513
Chore: Comment cleanup
Superkat32 Aug 1, 2026
9d92759
Fix: Fix horizontal scrolling not being capped properly, inserting a …
Superkat32 Aug 1, 2026
6100a24
Chore: Little bit of cleanup & docs
Superkat32 Aug 1, 2026
11aa0d2
Feat: Use new GlowcaseMultilineEditBox in NoteEditScreen
Superkat32 Aug 2, 2026
009a849
Chore: The great NoteEditScreen comment cleanup
Superkat32 Aug 2, 2026
f5d9326
Feat: Make PopupBlockEditScreen use new GlowcaseMultilineEditBox
Superkat32 Aug 2, 2026
9db7ea5
Chore: Popup block edit screen comment cleanup
Superkat32 Aug 2, 2026
47bdd6d
Feat: Show Popup Block's Title on PopupBlockViewScreen, and vertical …
Superkat32 Aug 3, 2026
ead3dbd
Chore: Optimize imports I think I did this like 5 hours ago
Superkat32 Aug 3, 2026
f5ea2d0
Feat: Begin Text Block ribbon tabs
Superkat32 Aug 5, 2026
45cab46
Chore: Comment cleanup & some JavaDocs
Superkat32 Aug 5, 2026
8fd7225
Feat: Continue work on Text Block tabs
Superkat32 Aug 6, 2026
c956e4c
Refactor: TextWidgets List isn't needed anymore
Superkat32 Aug 6, 2026
3c289d4
Feat: Continue work on View Tab widgets
Superkat32 Aug 8, 2026
71beff4
Feat: Update Vec3FieldsWidget with builder & options, add DegreeRotat…
Superkat32 Aug 9, 2026
7858825
Chore: Cleanup comments
Superkat32 Aug 9, 2026
e065f06
Feat: Insert Font tag button
Superkat32 Aug 9, 2026
502ef85
Feat: Fix some issues with SuggestionListWidget for the Text Screen, …
Superkat32 Aug 9, 2026
af1e505
Feat: EditableSliderWidget (A slider which can be right-clicked to be…
Superkat32 Aug 10, 2026
574b73b
Feat: Add text block offsets & rotations, allow InputFilter prefix to…
Superkat32 Aug 10, 2026
5a33cd4
Feat: Creature of Whimsy
Superkat32 Aug 11, 2026
c066723
TODO (Anchor Controls) - Leave comments for future TODOs on the ancho…
Superkat32 Aug 11, 2026
4de0e34
Fix: Ensure the edit box becomes focused after inserting a tag
Superkat32 Aug 11, 2026
1428358
Chore: Remove TextBlockOptionsScreen.java and cleanup other stuff lik…
Superkat32 Aug 11, 2026
fc9a07d
Feat: NumberEditBox(es), with ability to scroll to increment/decremen…
Superkat32 Aug 14, 2026
fbacb37
Chore: Some cleanup and fix integer box stack overflowing
Superkat32 Aug 14, 2026
5015d47
Feat: Add sounds to the number edit box for action feedback
Superkat32 Aug 14, 2026
f0e8081
Float point errors ruining my day!
Superkat32 Aug 15, 2026
cc1269d
Chore: Some extra cleanup & notes
Superkat32 Aug 17, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -15,12 +15,12 @@
import net.minecraft.world.level.storage.ValueOutput;

public class PopupBlockEntity extends GlowcaseBlockEntity {
public static final NodeParser PARSER = TagParser.DEFAULT;
public String title = "";
public List<Component> lines = new ArrayList<>();
public TextBlockEntity.TextAlignment textAlignment = TextBlockEntity.TextAlignment.CENTER;
public int color = 0xFFFFFFFF;
public boolean renderDirty = true;
public boolean viewScreenTitle = true;

public PopupBlockEntity(BlockPos pos, BlockState state) {
super(Glowcase.POPUP_BLOCK_ENTITY.get(), pos, state);
Expand All @@ -32,6 +32,7 @@ protected void saveAdditional(ValueOutput view) {
super.saveAdditional(view);

view.putString("title", this.title);
view.putBoolean("view_screen_title", this.viewScreenTitle);
view.putInt("color", this.color);

view.store("text_alignment", TextBlockEntity.TextAlignment.CODEC, this.textAlignment);
Expand All @@ -44,6 +45,7 @@ protected void loadAdditional(ValueInput view) {
super.loadAdditional(view);

this.title = view.getStringOr("title", "");
this.viewScreenTitle = view.getBooleanOr("view_screen_title", true);
this.color = view.getIntOr("color", 0xFFFFFF);

this.textAlignment = view.read("text_alignment", TextBlockEntity.TextAlignment.CODEC).orElse(TextBlockEntity.TextAlignment.CENTER);
Expand All @@ -52,39 +54,4 @@ protected void loadAdditional(ValueInput view) {

this.renderDirty = true;
}

public String getRawLine(int i) {
var line = this.lines.get(i);

if (line.getStyle() == null) {
return line.getString();
}

var insert = line.getStyle().getInsertion();

if (insert == null) {
return line.getString();
}
return insert;
}

public void addRawLine(int i, String string) {
var parsed = PARSER.parseComponent(string, ParserContext.of());

if (parsed.getString().equals(string)) {
this.lines.add(i, Component.literal(string));
} else {
this.lines.add(i, Component.empty().append(parsed).setStyle(Style.EMPTY.withInsertion(string)));
}
}

public void setRawLine(int i, String string) {
var parsed = PARSER.parseComponent(string, ParserContext.of());

if (parsed.getString().equals(string)) {
this.lines.set(i, Component.literal(string));
} else {
this.lines.set(i, Component.empty().append(parsed).setStyle(Style.EMPTY.withInsertion(string)));
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -18,23 +18,25 @@
import net.minecraft.world.level.block.state.BlockState;
import net.minecraft.world.level.storage.ValueInput;
import net.minecraft.world.level.storage.ValueOutput;
import net.minecraft.world.phys.Vec3;

import java.util.ArrayList;
import java.util.List;

public class TextBlockEntity extends GlowcaseBlockEntity {
public static final NodeParser PARSER = TagParser.DEFAULT;

public static final int PLATE_BACKGROUND = 0x44000000;

public List<Component> lines = new ArrayList<>();
// TODO (AC) - Anchor related field changes/additions (don't forget to save & load them!)
public TextAlignment textAlignment = TextAlignment.CENTER;
public HorizontalAlignment horizontalAlignment = HorizontalAlignment.CENTER;
public ZOffset zOffset = ZOffset.CENTER;
public boolean shadow = true;
public float scale = 1F;
public int color = ColorUtil.WHITE;
public int backgroundColor = 0;
public Vec3 offset = Vec3.ZERO;
public Vec3 rotation = Vec3.ZERO; // Yaw, pitch, roll

public TextBlockEntity(BlockPos pos, BlockState state) {
super(Glowcase.TEXT_BLOCK_ENTITY.get(), pos, state);
Expand All @@ -54,7 +56,10 @@ protected void saveAdditional(ValueOutput view) {
view.store("z_offset", ZOffset.CODEC, this.zOffset);
view.putBoolean("shadow", this.shadow);

view.store("lines", ComponentSerialization.CODEC.listOf(), lines);
view.store("lines", ComponentSerialization.CODEC.listOf(), this.lines);

view.store("offset", Vec3.CODEC, this.offset);
view.store("rotation", Vec3.CODEC, this.rotation);
}

@Override
Expand All @@ -69,53 +74,24 @@ protected void loadAdditional(ValueInput view) {

this.backgroundColor = view.getIntOr("background_color", 0);
this.shadow = view.getBooleanOr("shadow", true);
// TODO (AC) - Handle loading old data alignment and converting it into new justify/anchor/whatever data
this.textAlignment = view.read("text_alignment", TextAlignment.CODEC).orElse(TextAlignment.CENTER);
this.horizontalAlignment = view.read("horizontal_alignment", HorizontalAlignment.CODEC).orElse(HorizontalAlignment.CENTER);
this.zOffset = view.read("z_offset", ZOffset.CODEC).orElse(ZOffset.CENTER);
this.lines = new ArrayList<>(view.read("lines", ComponentSerialization.CODEC.listOf()).orElseGet(List::of));
this.rebake(false);
}

public String getRawLine(int i) {
var line = this.lines.get(i);

if (line.getStyle() == null) {
return line.getString();
}

var insert = line.getStyle().getInsertion();

if (insert == null) {
return line.getString();
}
return insert;
}

public void addRawLine(int i, String string) {
var parsed = PARSER.parseComponent(string, ParserContext.of());

if (parsed.getString().equals(string)) {
this.lines.add(i, Component.literal(string));
} else {
this.lines.add(i, Component.empty().append(parsed).setStyle(Style.EMPTY.withInsertion(string)));
}
}
this.offset = view.read("offset", Vec3.CODEC).orElse(Vec3.ZERO);
this.rotation = view.read("rotation", Vec3.CODEC).orElse(Vec3.ZERO);

public void setRawLine(int i, String string) {
var parsed = PARSER.parseComponent(string, ParserContext.of());

if (parsed.getString().equals(string)) {
this.lines.set(i, Component.literal(string));
} else {
this.lines.set(i, Component.empty().append(parsed).setStyle(Style.EMPTY.withInsertion(string)));
}
this.rebake(false);
}

public void rebake(boolean immediate) {
if (!this.hasLevel() || !this.getLevel().isClientSide()) return;
this.getLevel().sendBlockUpdated(this.getBlockPos(), this.getBlockState(), this.getBlockState(), immediate ? Block.UPDATE_IMMEDIATE : 0);
}

// TODO (AC) - Rename into TextJustify?
public enum TextAlignment implements StringRepresentable {
LEFT,
CENTER,
Expand All @@ -133,6 +109,8 @@ public String getSerializedName() {
}
}

// TODO (AC Idea) - Rename to "ZAnchor" to provide a clear distinction between xyz offset and this?
// If done, fields/variables and translations for the edit screen should be updated
public enum ZOffset implements StringRepresentable {
FRONT, CENTER, BACK;

Expand All @@ -144,6 +122,7 @@ public String getSerializedName() {
}
}

@Deprecated
public enum HorizontalAlignment implements StringRepresentable {
LEFT, CENTER, RIGHT;

Expand All @@ -155,4 +134,41 @@ public String getSerializedName() {
return name().toLowerCase();
}
}

public enum Anchor implements StringRepresentable {
TOP_LEFT(-1, 1), TOP(0, 1), TOP_RIGHT(1, 1),
MIDDLE_LEFT(-1, 0), MIDDLE(0, 0), MIDDLE_RIGHT(1, 0),
BOTTOM_LEFT(-1, -1), BOTTOM(0, -1), BOTTOM_RIGHT(1, -1);

public static final Codec<Anchor> CODEC = StringRepresentable.fromEnum(Anchor::values);
public static final StreamCodec<ByteBuf, Anchor> STREAM_CODEC = ByteBufCodecs.BYTE.map(index -> Anchor.values()[index], anchor -> (byte) anchor.ordinal());

public static Anchor fromHorizontalAlignment(HorizontalAlignment horizontalAlignment) {
return switch (horizontalAlignment) {
case LEFT -> MIDDLE_LEFT;
case RIGHT -> MIDDLE_RIGHT;
default -> MIDDLE;
};
}

private final int x;
private final int y;
Anchor(int x, int y) {
this.x = x;
this.y = y;
}

public int getX() {
return this.x;
}

public int getY() {
return this.y;
}

@Override
public String getSerializedName() {
return this.name().toLowerCase();
}
}
}
Original file line number Diff line number Diff line change
@@ -1,11 +1,81 @@
package dev.hephaestus.glowcase.client.gui.screen.ingame;

import dev.hephaestus.glowcase.client.gui.widget.ingame.ColorPickerWidget;
import net.minecraft.ChatFormatting;
import dev.hephaestus.glowcase.client.gui.widget.ingame.color.picker.ColorPickerWidget;
import net.minecraft.client.gui.GuiGraphicsExtractor;
import net.minecraft.client.gui.components.events.GuiEventListener;
import net.minecraft.client.gui.screens.Screen;
import net.minecraft.client.input.KeyEvent;
import net.minecraft.client.input.MouseButtonEvent;
import org.lwjgl.glfw.GLFW;

/**
* Main interface for any Screen wishing to implement a {@link ColorPickerWidget}.<br><br>
* Each ColorPickerIncludedScreen has *one* Color Picker widget which gets shared among all things using it.<br>
* Steps for adding a Color Picker to a screen:
* <ol type="0">
* <li>Implement this interface, and return a private ColorPickerWidget in {@link ColorPickerIncludedScreen#getColorPickerWidget()}.</li>
* <li>Initialize your ColorPickerWidget in {@link Screen#init()} via {@link ColorPickerWidget#builder(ColorPickerIncludedScreen)}. You do *not* need to add it as a renderableWidget.</li>
* <li>Include {@link ColorPickerIncludedScreen#extractColorPicker(GuiGraphicsExtractor, int, int, float)} at the very bottom of {@link Screen#extractRenderState(GuiGraphicsExtractor, int, int, float)} to ensure it renders atop of everything else.</li>
* <li>Include {@link ColorPickerIncludedScreen#mouseClickedColorPicker(MouseButtonEvent, boolean)} at the very top of {@link Screen#mouseClicked(MouseButtonEvent, boolean)}, return true if color picker was clicked, otherwise continue with method.</li>
* <li>Include {@link ColorPickerIncludedScreen#keyPressedColorPicker(KeyEvent)} at the very top of {@link Screen#keyPressed(KeyEvent)}, return true if color picker key pressed, otherwise continue with method.</li>
* <li>Booyah!</li>
* </ol>
* @author Superkat32
*/
public interface ColorPickerIncludedScreen {
ColorPickerWidget colorPickerWidget();
void toggleColorPicker(boolean active);
void insertHexTag(String hex);
void insertFormattingTag(ChatFormatting formatting);
ColorPickerWidget getColorPickerWidget();

default ColorPickerWidget createColorPickerWidget() {
return ColorPickerWidget.builder(this).build();
}

default void extractColorPicker(GuiGraphicsExtractor graphics, int mouseX, int mouseY, float delta) {
this.getColorPickerWidget().extractRenderState(graphics, mouseX, mouseY, delta);
}

default boolean mouseClickedColorPicker(MouseButtonEvent event, boolean doubleClick) {
double mouseX = event.x();
double mouseY = event.y();
ColorPickerWidget colorPickerWidget = this.getColorPickerWidget();

if (colorPickerWidget.isActive() && colorPickerWidget.visible) {
if (colorPickerWidget.isMouseOver(mouseX, mouseY)) {
colorPickerWidget.mouseClicked(event, doubleClick);
Screen self = (Screen) this;
self.setFocused(colorPickerWidget);
self.setDragging(true);
return true;
} else if (colorPickerWidget.targetElement == null || !colorPickerWidget.targetElement.isMouseOver(mouseX, mouseY)) {
this.hideColorPickerWidget();
}
}
return false;
}

default boolean keyPressedColorPicker(KeyEvent event) {
int keyCode = event.key();
ColorPickerWidget colorPickerWidget = this.getColorPickerWidget();
if (colorPickerWidget.isActive()) {
Screen self = (Screen) this;
switch (keyCode) {
case GLFW.GLFW_KEY_ENTER, GLFW.GLFW_KEY_KP_ENTER -> colorPickerWidget.confirm();
case GLFW.GLFW_KEY_ESCAPE -> colorPickerWidget.cancel();
default -> {
GuiEventListener pickerTarget = colorPickerWidget.targetElement;
if (pickerTarget != null) {
self.setFocused(pickerTarget);
pickerTarget.keyPressed(event);
return true;
}
}
}
self.setFocused(null);
return true;
}
return false;
}

default void hideColorPickerWidget() {
this.getColorPickerWidget().hide();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -34,8 +34,8 @@ public void init() {
this.itemWidget.setValue((this.blockEntity.isItemTag ? "#" : "") + item);
}
this.itemWidget.setHint(TextUtils.placeholder("gui.glowcase.item_or_tag"));
this.itemWidget.setFilter((currentValue, newChar, cursorPos) -> {
if (!InputFilters.assertOptionalPrefix('#', currentValue, newChar, cursorPos)) return false;
this.itemWidget.setFilter((currentValue, newChar, cursorPos, highlightPos) -> {
if (!InputFilters.assertOptionalPrefix('#', currentValue, newChar, cursorPos, highlightPos)) return false;
if (newChar == '#' && cursorPos == 0) return true;

return this.isValidCharacterForName(currentValue, newChar, cursorPos);
Expand Down
Loading
Loading