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

CyclopsMC / IntegratedDynamics / 15366166327

31 May 2025 05:58PM UTC coverage: 44.766% (-0.5%) from 45.303%
15366166327

push

github

rubensworks
Bump mod version

2565 of 8515 branches covered (30.12%)

Branch coverage included in aggregate %.

11734 of 23427 relevant lines covered (50.09%)

2.38 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.Helpers;
14
import org.cyclops.cyclopscore.helper.MinecraftHelpers;
15
import org.cyclops.cyclopscore.helper.RenderHelpers;
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
    @Getter
×
35
    private IDropdownEntry<T> selectedDropdownPossibility = null;
36
    @Getter
×
37
    @Setter
×
38
    private int dropdownSize = 5;
39
    @Getter
×
40
    @Setter
×
41
    private IDropdownEntryListener<T> dropdownEntryListener;
42

43
    private int enabledColor = 14737632;
×
44
    private int disabledColor = 7368816;
×
45

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

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

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

62
    public int getPossibilitiesCount() {
63
        return possibilities.size();
×
64
    }
65

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

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

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

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

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

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

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

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

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

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

189
                fontRenderer.drawInBatch("...", (float)x + 1, (float)cy + 2, disabledColor, true, guiGraphics.pose().last().pose(), guiGraphics.bufferSource(), Font.DisplayMode.NORMAL, 0, 15728880);
×
190

191
                cy += 10;
×
192
            }
193

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

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

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

215
                // Draw text
216
                fontRenderer.drawInBatch(displayPossibility.get(0), (float)x + 1, (float)cy + 2, active ? enabledColor : disabledColor, true, guiGraphics.pose().last().pose(), guiGraphics.bufferSource(), Font.DisplayMode.NORMAL, 0, 15728880);
×
217
                if(addTooltip) {
×
218
                    int tooltipLineOffsetY = 2;
×
219
                    for (Component tooltipLine : tooltipLines) {
×
220
                        tooltipLineOffsetY += yOffset;
×
221
                        fontRenderer.drawInBatch(tooltipLine.getString(), (float)x + 1, (float)cy + tooltipLineOffsetY, enabledColor, true, guiGraphics.pose().last().pose(), guiGraphics.bufferSource(), Font.DisplayMode.NORMAL, 0, 15728880);
×
222
                    }
×
223
                }
224

225
                cy += entryHeight;
×
226
            }
227

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

234
                fontRenderer.drawInBatch("...", (float)x + 1, (float)cy + 2, disabledColor, true, guiGraphics.pose().last().pose(), guiGraphics.bufferSource(), Font.DisplayMode.NORMAL, 0, 15728880);
×
235
            }
236
        }
237
    }
×
238

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

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

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

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

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

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

284
            cy += entryHeight;
×
285
        }
286

287
        return -1;
×
288
    }
289

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