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

CyclopsMC / IntegratedDynamics / 22186773560

19 Feb 2026 02:52PM UTC coverage: 52.603% (+0.2%) from 52.363%
22186773560

push

github

web-flow
Remove Lombok dependency (#1604)

2911 of 8664 branches covered (33.6%)

Branch coverage included in aggregate %.

17683 of 30486 relevant lines covered (58.0%)

3.01 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 net.minecraft.client.Minecraft;
5
import net.minecraft.client.gui.Font;
6
import net.minecraft.client.gui.GuiGraphics;
7
import net.minecraft.client.input.CharacterEvent;
8
import net.minecraft.client.input.KeyEvent;
9
import net.minecraft.client.input.MouseButtonEvent;
10
import net.minecraft.network.chat.Component;
11
import net.minecraft.network.chat.MutableComponent;
12
import net.minecraft.util.ARGB;
13
import net.minecraft.util.FormattedCharSequence;
14
import org.cyclops.cyclopscore.client.gui.component.input.WidgetTextFieldExtended;
15
import org.cyclops.cyclopscore.helper.IModHelpers;
16
import org.lwjgl.glfw.GLFW;
17

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

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

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

38
    private int enabledColor = ARGB.opaque(14737632);
×
39
    private int disabledColor = ARGB.opaque(7368816);
×
40

41
    public IDropdownEntry<T> getSelectedDropdownPossibility() {
42
        return selectedDropdownPossibility;
×
43
    }
44

45
    public int getDropdownSize() {
46
        return dropdownSize;
×
47
    }
48

49
    public void setDropdownSize(int dropdownSize) {
50
        this.dropdownSize = dropdownSize;
×
51
    }
×
52

53
    public IDropdownEntryListener<T> getDropdownEntryListener() {
54
        return dropdownEntryListener;
×
55
    }
56

57
    public void setDropdownEntryListener(IDropdownEntryListener<T> dropdownEntryListener) {
58
        this.dropdownEntryListener = dropdownEntryListener;
×
59
    }
×
60

61
    public WidgetTextFieldDropdown(Font fontrenderer, int x, int y, int width, int height,
62
                                   Component narrationMessage, boolean background, Set<IDropdownEntry<T>> possibilities) {
63
        super(fontrenderer, x, y, width, height, narrationMessage, background);
×
64
        setPossibilities(Objects.requireNonNull(possibilities));
×
65
    }
×
66

67
    public WidgetTextFieldDropdown(Font fontrenderer, int x, int y, int width, int height,
68
                                   Component narrationMessage, boolean background) {
69
        this(fontrenderer, x, y, width, height, narrationMessage, background, Collections.emptySet());
×
70
    }
×
71

72
    public void setPossibilities(Set<IDropdownEntry<T>> possibilities) {
73
        this.possibilities = possibilities;
×
74
        this.visiblePossibilities = Collections.emptyList();
×
75
    }
×
76

77
    public int getPossibilitiesCount() {
78
        return possibilities.size();
×
79
    }
80

81
    @Nullable
82
    public IDropdownEntry<T> getVisiblePossibility(int index) {
83
        return visiblePossibilities.get(index);
×
84
    }
85

86
    public void refreshDropdownList() {
87
        // Remove all colors and formatting when changing text
88
        if(getValue().contains("§")) {
×
89
            setValue(getValue().replaceAll("§.", ""));
×
90
        }
91
        if (!possibilities.isEmpty()) {
×
92
            visiblePossibilities = Lists.newArrayList();
×
93
            for (IDropdownEntry<T> possibility : possibilities) {
×
94
                if (possibility.getMatchString().toLowerCase().contains(getValue().toLowerCase())) {
×
95
                    visiblePossibilities.add(possibility);
×
96
                }
97
            }
×
98
            visiblePossibilitiesIndex = -1;
×
99
            if (!visiblePossibilities.isEmpty()) {
×
100
                selectedDropdownPossibility = visiblePossibilities.stream()
×
101
                        .filter(e -> e.getMatchString().equals(getValue()))
×
102
                        .findFirst()
×
103
                        .orElse(null);
×
104
            }
105
            if (dropdownEntryListener != null) {
×
106
                dropdownEntryListener.onSetDropdownPossiblity(selectedDropdownPossibility);
×
107
            }
108
        }
109
    }
×
110
    @Override
111
    public void setFocused(boolean isFocusedIn) {
112
        super.setFocused(isFocusedIn);
×
113
        if (isFocusedIn) {
×
114
            refreshDropdownList();
×
115
        }
116
    }
×
117

118
    @Override
119
    public boolean charTyped(CharacterEvent evt) {
120
        if (super.charTyped(evt)) {
×
121
            refreshDropdownList();
×
122
            return true;
×
123
        }
124
        return false;
×
125
    }
126

127
    @Override
128
    public boolean keyPressed(KeyEvent evt) {
129
        IDropdownEntry<T> oldPossibility = selectedDropdownPossibility;
×
130
        selectedDropdownPossibility = null;
×
131
        if (!possibilities.isEmpty()) {
×
132
            switch (evt.key()) {
×
133
                case GLFW.GLFW_KEY_UP:
134
                    if (visiblePossibilitiesIndex >= 0) {
×
135
                        visiblePossibilitiesIndex--;
×
136
                    } else {
137
                        visiblePossibilitiesIndex = visiblePossibilities.size() - 1;
×
138
                    }
139
                    return true;
×
140
                case GLFW.GLFW_KEY_TAB:
141
                case GLFW.GLFW_KEY_DOWN:
142
                    if (visiblePossibilitiesIndex < visiblePossibilities.size() - 1) {
×
143
                        visiblePossibilitiesIndex++;
×
144
                    } else {
145
                        visiblePossibilitiesIndex = 0;
×
146
                    }
147
                    return true;
×
148
                case GLFW.GLFW_KEY_KP_ENTER:
149
                case GLFW.GLFW_KEY_ENTER:
150
                case GLFW.GLFW_KEY_RIGHT:
151
                    if (visiblePossibilitiesIndex >= 0
×
152
                            && visiblePossibilitiesIndex < visiblePossibilities.size()) {
×
153
                        selectVisiblePossibility(visiblePossibilitiesIndex);
×
154
                        return true;
×
155
                    }
156
            }
157
        }
158
        if (super.keyPressed(evt)) {
×
159
            refreshDropdownList();
×
160
            return true;
×
161
        }
162
        selectedDropdownPossibility = oldPossibility;
×
163
        return false;
×
164
    }
165

166
    protected void selectVisiblePossibility(int index) {
167
        visiblePossibilitiesIndex = index;
×
168
        selectPossibility(visiblePossibilities.get(visiblePossibilitiesIndex));
×
169
    }
×
170

171
    public void selectPossibility(@Nullable IDropdownEntry<T> entry) {
172
        selectedDropdownPossibility = entry;
×
173
        setValue(selectedDropdownPossibility != null ? selectedDropdownPossibility.getDisplayString().getString() : "");
×
174
        visiblePossibilities = Lists.newArrayList();
×
175
        visiblePossibilitiesIndex = -1;
×
176
        if (dropdownEntryListener != null) {
×
177
            dropdownEntryListener.onSetDropdownPossiblity(selectedDropdownPossibility);
×
178
        }
179
    }
×
180

181
    @Override
182
    public void renderWidget(GuiGraphics guiGraphics, int mouseX, int mouseY, float partialTicks) {
183
        // Display text red that is in an "invalid" state (no valid dropdrown entry selected)
184
        this.setTextColor(this.selectedDropdownPossibility == null ? IModHelpers.get().getBaseHelpers().RGBAToInt(220, 10, 10, 255) : ARGB.opaque(14737632));
×
185

186
        super.renderWidget(guiGraphics, mouseX, mouseY, partialTicks);
×
187
        if (this.isVisible() && isFocused()) {
×
188
            Font fontRenderer = Minecraft.getInstance().font;
×
189
            int yOffset = fontRenderer.lineHeight + 3;
×
190

191
            int x = this.getX();
×
192
            int y = this.getY() + yOffset;
×
193
            int width = this.getWidth() + 9;
×
194
            int startIndex = Math.max(0, Math.min(visiblePossibilitiesIndex, visiblePossibilities.size() - getDropdownSize()));
×
195
            int endIndex = Math.min(startIndex + getDropdownSize(), visiblePossibilities.size());
×
196
            int cy = y;
×
197

198
            // Draw ... if we are not at the first element
199
            if (startIndex > 0) {
×
200
                // Draw background
201
                guiGraphics.fill(x, cy - 1, x + width, cy + 11, -6250336);
×
202
                guiGraphics.fill(x - 1, cy, x + width - 1, cy + 10, -16777216);
×
203

204
                guiGraphics.drawString(fontRenderer, "...", x + 1, cy + 2, disabledColor, true);
×
205

206
                cy += 10;
×
207
            }
208

209
            for (int i = startIndex; i < endIndex; i++) {
×
210
                // Initialize entry
211
                IDropdownEntry<?> dropdownEntry = visiblePossibilities.get(i);
×
212
                MutableComponent possibility = dropdownEntry.getDisplayString();
×
213
                List<FormattedCharSequence> displayPossibility = fontRenderer.split(possibility, width);
×
214
                boolean active = visiblePossibilitiesIndex == i;
×
215
                int entryHeight = yOffset;
×
216

217
                // Optionally initialize tooltip
218
                boolean addTooltip = (active && IModHelpers.get().getMinecraftClientHelpers().isShifted())
×
219
                        || IModHelpers.get().getRenderHelpers().isPointInRegion(x, cy, getWidth(), yOffset, mouseX, mouseY);
×
220
                List<MutableComponent> tooltipLines = null;
×
221
                if (addTooltip) {
×
222
                    tooltipLines = dropdownEntry.getTooltip();
×
223
                    entryHeight += tooltipLines.size() * yOffset;
×
224
                }
225

226
                // Draw background
227
                guiGraphics.fill(x, cy - 1, x + width, cy + entryHeight + 1, -6250336);
×
228
                guiGraphics.fill(x - 1, cy, x + width - 1, cy + entryHeight, -16777216);
×
229

230
                // Draw text
231
                guiGraphics.drawString(fontRenderer, displayPossibility.get(0), x + 1, cy + 2, active ? enabledColor : disabledColor, true);
×
232
                if(addTooltip) {
×
233
                    int tooltipLineOffsetY = 2;
×
234
                    for (Component tooltipLine : tooltipLines) {
×
235
                        tooltipLineOffsetY += yOffset;
×
236
                        guiGraphics.drawString(fontRenderer, tooltipLine.getString(), x + 1, cy + tooltipLineOffsetY, enabledColor, true);
×
237
                    }
×
238
                }
239

240
                cy += entryHeight;
×
241
            }
242

243
            // Draw ... if we haven't reached the end of the list
244
            if (endIndex < visiblePossibilities.size()) {
×
245
                // Draw background
246
                guiGraphics.fill(x, cy - 1, x + width, cy + 11, -6250336);
×
247
                guiGraphics.fill(x - 1, cy, x + width - 1, cy + 10, -16777216);
×
248

249
                guiGraphics.drawString(fontRenderer, "...", x + 1, cy + 2, disabledColor, true);
×
250
            }
251
        }
252
    }
×
253

254
    @Override
255
    public boolean mouseClicked(MouseButtonEvent evt, boolean isDoubleClick) {
256
        if (this.isVisible() && isFocused()) {
×
257
            int i = getHoveredVisiblePossibility(evt.x(), evt.y());
×
258
            if (i >= 0) {
×
259
                selectVisiblePossibility(i);
×
260
                return true;
×
261
            }
262
        }
263
        return super.mouseClicked(evt, isDoubleClick);
×
264
    }
265

266
    public int getHoveredVisiblePossibility(double mouseX, double mouseY) {
267
        Font fontRenderer = Minecraft.getInstance().gui.getFont();
×
268
        int yOffset = fontRenderer.lineHeight + 3;
×
269

270
        int x = this.getX();
×
271
        int y = this.getY() + yOffset;
×
272
        int startIndex = Math.max(0, Math.min(visiblePossibilitiesIndex, visiblePossibilities.size() - getDropdownSize()));
×
273
        int endIndex = Math.min(startIndex + getDropdownSize(), visiblePossibilities.size());
×
274
        int cy = y;
×
275

276
        // Draw ... if we are not at the first element
277
        if (startIndex > 0) {
×
278
            cy += 10;
×
279
        }
280

281
        for (int i = startIndex; i < endIndex; i++) {
×
282
            // Initialize entry
283
            IDropdownEntry<?> dropdownEntry = visiblePossibilities.get(i);
×
284
            boolean active = visiblePossibilitiesIndex == i;
×
285
            int entryHeight = yOffset;
×
286

287
            // Optionally initialize tooltip
288
            boolean addTooltip = (active && IModHelpers.get().getMinecraftClientHelpers().isShifted())
×
289
                    || IModHelpers.get().getRenderHelpers().isPointInRegion(x, cy, getWidth(), yOffset, mouseX, mouseY);
×
290
            if (IModHelpers.get().getRenderHelpers().isPointInRegion(x, cy, getWidth(), yOffset, mouseX, mouseY)) {
×
291
                return i;
×
292
            }
293
            List<MutableComponent> tooltipLines = null;
×
294
            if (addTooltip) {
×
295
                tooltipLines = dropdownEntry.getTooltip();
×
296
                entryHeight += tooltipLines.size() * yOffset;
×
297
            }
298

299
            cy += entryHeight;
×
300
        }
301

302
        return -1;
×
303
    }
304

305
}
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