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

CyclopsMC / IntegratedDynamics / 20210191346

14 Dec 2025 03:32PM UTC coverage: 19.514% (-33.5%) from 53.061%
20210191346

push

github

rubensworks
Remove deprecations

663 of 8728 branches covered (7.6%)

Branch coverage included in aggregate %.

6786 of 29445 relevant lines covered (23.05%)

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

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

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

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

45
    private int enabledColor = ARGB.opaque(14737632);
×
46
    private int disabledColor = ARGB.opaque(7368816);
×
47

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

54
    public WidgetTextFieldDropdown(Font fontrenderer, int x, int y, int width, int height,
55
                                   Component narrationMessage, boolean background) {
56
        this(fontrenderer, x, y, width, height, narrationMessage, background, Collections.emptySet());
×
57
    }
×
58

59
    public void setPossibilities(Set<IDropdownEntry<T>> possibilities) {
60
        this.possibilities = possibilities;
×
61
        this.visiblePossibilities = Collections.emptyList();
×
62
    }
×
63

64
    public int getPossibilitiesCount() {
65
        return possibilities.size();
×
66
    }
67

68
    @Nullable
69
    public IDropdownEntry<T> getVisiblePossibility(int index) {
70
        return visiblePossibilities.get(index);
×
71
    }
72

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

105
    @Override
106
    public boolean charTyped(CharacterEvent evt) {
107
        if (super.charTyped(evt)) {
×
108
            refreshDropdownList();
×
109
            return true;
×
110
        }
111
        return false;
×
112
    }
113

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

153
    protected void selectVisiblePossibility(int index) {
154
        visiblePossibilitiesIndex = index;
×
155
        selectPossibility(visiblePossibilities.get(visiblePossibilitiesIndex));
×
156
    }
×
157

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

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

173
        super.renderWidget(guiGraphics, mouseX, mouseY, partialTicks);
×
174
        if (this.isVisible() && isFocused()) {
×
175
            Font fontRenderer = Minecraft.getInstance().font;
×
176
            int yOffset = fontRenderer.lineHeight + 3;
×
177

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

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

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

193
                cy += 10;
×
194
            }
195

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

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

213
                // Draw background
214
                guiGraphics.fill(x, cy - 1, x + width, cy + entryHeight + 1, -6250336);
×
215
                guiGraphics.fill(x - 1, cy, x + width - 1, cy + entryHeight, -16777216);
×
216

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

227
                cy += entryHeight;
×
228
            }
229

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

236
                guiGraphics.drawString(fontRenderer, "...", x + 1, cy + 2, disabledColor, true);
×
237
            }
238
        }
239
    }
×
240

241
    @Override
242
    public boolean mouseClicked(MouseButtonEvent evt, boolean isDoubleClick) {
243
        if (this.isVisible() && isFocused()) {
×
244
            int i = getHoveredVisiblePossibility(evt.x(), evt.y());
×
245
            if (i >= 0) {
×
246
                selectVisiblePossibility(i);
×
247
                return true;
×
248
            }
249
        }
250
        return super.mouseClicked(evt, isDoubleClick);
×
251
    }
252

253
    public int getHoveredVisiblePossibility(double mouseX, double mouseY) {
254
        Font fontRenderer = Minecraft.getInstance().gui.getFont();
×
255
        int yOffset = fontRenderer.lineHeight + 3;
×
256

257
        int x = this.getX();
×
258
        int y = this.getY() + yOffset;
×
259
        int startIndex = Math.max(0, Math.min(visiblePossibilitiesIndex, visiblePossibilities.size() - getDropdownSize()));
×
260
        int endIndex = Math.min(startIndex + getDropdownSize(), visiblePossibilities.size());
×
261
        int cy = y;
×
262

263
        // Draw ... if we are not at the first element
264
        if (startIndex > 0) {
×
265
            cy += 10;
×
266
        }
267

268
        for (int i = startIndex; i < endIndex; i++) {
×
269
            // Initialize entry
270
            IDropdownEntry<?> dropdownEntry = visiblePossibilities.get(i);
×
271
            boolean active = visiblePossibilitiesIndex == i;
×
272
            int entryHeight = yOffset;
×
273

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

286
            cy += entryHeight;
×
287
        }
288

289
        return -1;
×
290
    }
291

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