• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

CyclopsMC / IntegratedDynamics / 15366205963

31 May 2025 06:03PM UTC coverage: 45.019% (-0.5%) from 45.524%
15366205963

push

github

rubensworks
Merge remote-tracking branch 'origin/master-1.21-lts' into master-1.21

2555 of 8509 branches covered (30.03%)

Branch coverage included in aggregate %.

11885 of 23566 relevant lines covered (50.43%)

2.4 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

0.0
/src/main/java/org/cyclops/integrateddynamics/core/client/gui/WidgetTextFieldDropdown.java
1
package org.cyclops.integrateddynamics.core.client.gui;
2

3
import com.google.common.collect.Lists;
4
import lombok.Getter;
5
import lombok.Setter;
6
import net.minecraft.client.Minecraft;
7
import net.minecraft.client.gui.Font;
8
import net.minecraft.client.gui.GuiGraphics;
9
import net.minecraft.network.chat.Component;
10
import net.minecraft.network.chat.MutableComponent;
11
import net.minecraft.util.FormattedCharSequence;
12
import org.cyclops.cyclopscore.client.gui.component.input.WidgetTextFieldExtended;
13
import org.cyclops.cyclopscore.helper.IModHelpers;
14
import org.lwjgl.glfw.GLFW;
15

16
import javax.annotation.Nullable;
17
import java.util.Collections;
18
import java.util.List;
19
import java.util.Objects;
20
import java.util.Set;
21

22
/**
23
 * A text field that can show a dropdown for autocomplete.
24
 * @param <T> The dropdown entry type.
25
 * @author rubensworks
26
 */
27
public class WidgetTextFieldDropdown<T> extends WidgetTextFieldExtended {
28

29
    private Set<IDropdownEntry<T>> possibilities;
30
    private List<IDropdownEntry<T>> visiblePossibilities = Collections.emptyList();
×
31
    private int visiblePossibilitiesIndex = -1;
×
32
    @Getter
×
33
    private IDropdownEntry<T> selectedDropdownPossibility = null;
34
    @Getter
×
35
    @Setter
×
36
    private int dropdownSize = 5;
37
    @Getter
×
38
    @Setter
×
39
    private IDropdownEntryListener<T> dropdownEntryListener;
40

41
    private int enabledColor = 14737632;
×
42
    private int disabledColor = 7368816;
×
43

44
    public WidgetTextFieldDropdown(Font fontrenderer, int x, int y, int width, int height,
45
                                   Component narrationMessage, boolean background, Set<IDropdownEntry<T>> possibilities) {
46
        super(fontrenderer, x, y, width, height, narrationMessage, background);
×
47
        setPossibilities(Objects.requireNonNull(possibilities));
×
48
    }
×
49

50
    public WidgetTextFieldDropdown(Font fontrenderer, int x, int y, int width, int height,
51
                                   Component narrationMessage, boolean background) {
52
        this(fontrenderer, x, y, width, height, narrationMessage, background, Collections.emptySet());
×
53
    }
×
54

55
    public void setPossibilities(Set<IDropdownEntry<T>> possibilities) {
56
        this.possibilities = possibilities;
×
57
        this.visiblePossibilities = Collections.emptyList();
×
58
    }
×
59

60
    public int getPossibilitiesCount() {
61
        return possibilities.size();
×
62
    }
63

64
    @Nullable
65
    public IDropdownEntry<T> getVisiblePossibility(int index) {
66
        return visiblePossibilities.get(index);
×
67
    }
68

69
    public void refreshDropdownList() {
70
        // Remove all colors and formatting when changing text
71
        if(getValue().contains("§")) {
×
72
            setValue(getValue().replaceAll("§.", ""));
×
73
        }
74
        if (!possibilities.isEmpty()) {
×
75
            visiblePossibilities = Lists.newArrayList();
×
76
            for (IDropdownEntry<T> possibility : possibilities) {
×
77
                if (possibility.getMatchString().toLowerCase().contains(getValue().toLowerCase())) {
×
78
                    visiblePossibilities.add(possibility);
×
79
                }
80
            }
×
81
            visiblePossibilitiesIndex = -1;
×
82
            if (!visiblePossibilities.isEmpty()) {
×
83
                selectedDropdownPossibility = visiblePossibilities.stream()
×
84
                        .filter(e -> e.getMatchString().equals(getValue()))
×
85
                        .findFirst()
×
86
                        .orElse(null);
×
87
            }
88
            if (dropdownEntryListener != null) {
×
89
                dropdownEntryListener.onSetDropdownPossiblity(selectedDropdownPossibility);
×
90
            }
91
        }
92
    }
×
93
    @Override
94
    public void setFocused(boolean isFocusedIn) {
95
        super.setFocused(isFocusedIn);
×
96
        if (isFocusedIn) {
×
97
            refreshDropdownList();
×
98
        }
99
    }
×
100

101
    @Override
102
    public boolean charTyped(char typedChar, int keyCode) {
103
        if (super.charTyped(typedChar, keyCode)) {
×
104
            refreshDropdownList();
×
105
            return true;
×
106
        }
107
        return false;
×
108
    }
109

110
    @Override
111
    public boolean keyPressed(int typedChar, int keyCode, int modifiers) {
112
        IDropdownEntry<T> oldPossibility = selectedDropdownPossibility;
×
113
        selectedDropdownPossibility = null;
×
114
        if (!possibilities.isEmpty()) {
×
115
            switch (typedChar) {
×
116
                case GLFW.GLFW_KEY_UP:
117
                    if (visiblePossibilitiesIndex >= 0) {
×
118
                        visiblePossibilitiesIndex--;
×
119
                    } else {
120
                        visiblePossibilitiesIndex = visiblePossibilities.size() - 1;
×
121
                    }
122
                    return true;
×
123
                case GLFW.GLFW_KEY_TAB:
124
                case GLFW.GLFW_KEY_DOWN:
125
                    if (visiblePossibilitiesIndex < visiblePossibilities.size() - 1) {
×
126
                        visiblePossibilitiesIndex++;
×
127
                    } else {
128
                        visiblePossibilitiesIndex = 0;
×
129
                    }
130
                    return true;
×
131
                case GLFW.GLFW_KEY_KP_ENTER:
132
                case GLFW.GLFW_KEY_ENTER:
133
                case GLFW.GLFW_KEY_RIGHT:
134
                    if (visiblePossibilitiesIndex >= 0
×
135
                            && visiblePossibilitiesIndex < visiblePossibilities.size()) {
×
136
                        selectVisiblePossibility(visiblePossibilitiesIndex);
×
137
                        return true;
×
138
                    }
139
            }
140
        }
141
        if (super.keyPressed(typedChar, keyCode, modifiers)) {
×
142
            refreshDropdownList();
×
143
            return true;
×
144
        }
145
        selectedDropdownPossibility = oldPossibility;
×
146
        return false;
×
147
    }
148

149
    protected void selectVisiblePossibility(int index) {
150
        visiblePossibilitiesIndex = index;
×
151
        selectPossibility(visiblePossibilities.get(visiblePossibilitiesIndex));
×
152
    }
×
153

154
    public void selectPossibility(@Nullable IDropdownEntry<T> entry) {
155
        selectedDropdownPossibility = entry;
×
156
        setValue(selectedDropdownPossibility != null ? selectedDropdownPossibility.getDisplayString().getString() : "");
×
157
        visiblePossibilities = Lists.newArrayList();
×
158
        visiblePossibilitiesIndex = -1;
×
159
        if (dropdownEntryListener != null) {
×
160
            dropdownEntryListener.onSetDropdownPossiblity(selectedDropdownPossibility);
×
161
        }
162
    }
×
163

164
    @Override
165
    public void renderWidget(GuiGraphics guiGraphics, int mouseX, int mouseY, float partialTicks) {
166
        // Display text red that is in an "invalid" state (no valid dropdrown entry selected)
167
        this.setTextColor(this.selectedDropdownPossibility == null ? IModHelpers.get().getBaseHelpers().RGBToInt(220, 10, 10) : 14737632);
×
168

169
        super.renderWidget(guiGraphics, mouseX, mouseY, partialTicks);
×
170
        if (this.isVisible() && isFocused()) {
×
171
            Font fontRenderer = Minecraft.getInstance().font;
×
172
            int yOffset = fontRenderer.lineHeight + 3;
×
173

174
            int x = this.getX();
×
175
            int y = this.getY() + yOffset;
×
176
            int width = this.getWidth() + 9;
×
177
            int startIndex = Math.max(0, Math.min(visiblePossibilitiesIndex, visiblePossibilities.size() - getDropdownSize()));
×
178
            int endIndex = Math.min(startIndex + getDropdownSize(), visiblePossibilities.size());
×
179
            int cy = y;
×
180

181
            // Draw ... if we are not at the first element
182
            if (startIndex > 0) {
×
183
                // Draw background
184
                guiGraphics.fill(x, cy - 1, x + width, cy + 11, -6250336);
×
185
                guiGraphics.fill(x - 1, cy, x + width - 1, cy + 10, -16777216);
×
186

187
                guiGraphics.drawString(fontRenderer, "...", (float)x + 1, (float)cy + 2, disabledColor, true);
×
188

189
                cy += 10;
×
190
            }
191

192
            for (int i = startIndex; i < endIndex; i++) {
×
193
                // Initialize entry
194
                IDropdownEntry<?> dropdownEntry = visiblePossibilities.get(i);
×
195
                MutableComponent possibility = dropdownEntry.getDisplayString();
×
196
                List<FormattedCharSequence> displayPossibility = fontRenderer.split(possibility, width);
×
197
                boolean active = visiblePossibilitiesIndex == i;
×
198
                int entryHeight = yOffset;
×
199

200
                // Optionally initialize tooltip
201
                boolean addTooltip = (active && IModHelpers.get().getMinecraftClientHelpers().isShifted())
×
202
                        || IModHelpers.get().getRenderHelpers().isPointInRegion(x, cy, getWidth(), yOffset, mouseX, mouseY);
×
203
                List<MutableComponent> tooltipLines = null;
×
204
                if (addTooltip) {
×
205
                    tooltipLines = dropdownEntry.getTooltip();
×
206
                    entryHeight += tooltipLines.size() * yOffset;
×
207
                }
208

209
                // Draw background
210
                guiGraphics.fill(x, cy - 1, x + width, cy + entryHeight + 1, -6250336);
×
211
                guiGraphics.fill(x - 1, cy, x + width - 1, cy + entryHeight, -16777216);
×
212

213
                // Draw text
214
                guiGraphics.drawString(fontRenderer, displayPossibility.get(0), (float)x + 1, (float)cy + 2, active ? enabledColor : disabledColor, true);
×
215
                if(addTooltip) {
×
216
                    int tooltipLineOffsetY = 2;
×
217
                    for (Component tooltipLine : tooltipLines) {
×
218
                        tooltipLineOffsetY += yOffset;
×
219
                        guiGraphics.drawString(fontRenderer, tooltipLine.getString(), (float)x + 1, (float)cy + tooltipLineOffsetY, enabledColor, true);
×
220
                    }
×
221
                }
222

223
                cy += entryHeight;
×
224
            }
225

226
            // Draw ... if we haven't reached the end of the list
227
            if (endIndex < visiblePossibilities.size()) {
×
228
                // Draw background
229
                guiGraphics.fill(x, cy - 1, x + width, cy + 11, -6250336);
×
230
                guiGraphics.fill(x - 1, cy, x + width - 1, cy + 10, -16777216);
×
231

232
                guiGraphics.drawString(fontRenderer, "...", (float)x + 1, (float)cy + 2, disabledColor, true);
×
233
            }
234
        }
235
    }
×
236

237
    @Override
238
    public boolean mouseClicked(double mouseX, double mouseY, int mouseButton) {
239
        if (this.isVisible() && isFocused()) {
×
240
            int i = getHoveredVisiblePossibility(mouseX, mouseY);
×
241
            if (i >= 0) {
×
242
                selectVisiblePossibility(i);
×
243
                return true;
×
244
            }
245
        }
246
        return super.mouseClicked(mouseX, mouseY, mouseButton);
×
247
    }
248

249
    public int getHoveredVisiblePossibility(double mouseX, double mouseY) {
250
        Font fontRenderer = Minecraft.getInstance().gui.getFont();
×
251
        int yOffset = fontRenderer.lineHeight + 3;
×
252

253
        int x = this.getX();
×
254
        int y = this.getY() + yOffset;
×
255
        int startIndex = Math.max(0, Math.min(visiblePossibilitiesIndex, visiblePossibilities.size() - getDropdownSize()));
×
256
        int endIndex = Math.min(startIndex + getDropdownSize(), visiblePossibilities.size());
×
257
        int cy = y;
×
258

259
        // Draw ... if we are not at the first element
260
        if (startIndex > 0) {
×
261
            cy += 10;
×
262
        }
263

264
        for (int i = startIndex; i < endIndex; i++) {
×
265
            // Initialize entry
266
            IDropdownEntry<?> dropdownEntry = visiblePossibilities.get(i);
×
267
            boolean active = visiblePossibilitiesIndex == i;
×
268
            int entryHeight = yOffset;
×
269

270
            // Optionally initialize tooltip
271
            boolean addTooltip = (active && IModHelpers.get().getMinecraftClientHelpers().isShifted())
×
272
                    || IModHelpers.get().getRenderHelpers().isPointInRegion(x, cy, getWidth(), yOffset, mouseX, mouseY);
×
273
            if (IModHelpers.get().getRenderHelpers().isPointInRegion(x, cy, getWidth(), yOffset, mouseX, mouseY)) {
×
274
                return i;
×
275
            }
276
            List<MutableComponent> tooltipLines = null;
×
277
            if (addTooltip) {
×
278
                tooltipLines = dropdownEntry.getTooltip();
×
279
                entryHeight += tooltipLines.size() * yOffset;
×
280
            }
281

282
            cy += entryHeight;
×
283
        }
284

285
        return -1;
×
286
    }
287

288
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc