diff --git a/src/main/java/betterquesting/api2/client/gui/panels/lists/CanvasScrolling.java b/src/main/java/betterquesting/api2/client/gui/panels/lists/CanvasScrolling.java index e8911e6eb..97fa158a3 100644 --- a/src/main/java/betterquesting/api2/client/gui/panels/lists/CanvasScrolling.java +++ b/src/main/java/betterquesting/api2/client/gui/panels/lists/CanvasScrolling.java @@ -18,7 +18,8 @@ import java.util.concurrent.CopyOnWriteArrayList; public class CanvasScrolling implements IGuiCanvas { - private final List guiPanels = new CopyOnWriteArrayList<>(); + + protected final List guiPanels = new CopyOnWriteArrayList<>(); private final IGuiRect transform; private boolean enabled = true; @@ -50,7 +51,7 @@ public class CanvasScrolling implements IGuiCanvas { // Enables the auto-disabling panels outside the cropped region. Useful for very large lists private boolean useBlocking = true; - private final CanvasCullingManager cullingManager = new CanvasCullingManager(); + protected final CanvasCullingManager cullingManager = new CanvasCullingManager(); private final GuiRectangle refRect = new GuiRectangle(0, 0, 0, 0); public CanvasScrolling(IGuiRect rect) { @@ -410,8 +411,8 @@ public boolean onKeyTyped(char c, int keycode) { break; } } - - /*if(!used && c == 'c') + + /*if(!used && c == 'c') { setScrollX(0); setScrollY(0); diff --git a/src/main/java/betterquesting/api2/client/gui/panels/lists/CanvasScrollingBuffered.java b/src/main/java/betterquesting/api2/client/gui/panels/lists/CanvasScrollingBuffered.java new file mode 100644 index 000000000..21a853870 --- /dev/null +++ b/src/main/java/betterquesting/api2/client/gui/panels/lists/CanvasScrollingBuffered.java @@ -0,0 +1,40 @@ +package betterquesting.api2.client.gui.panels.lists; + +import java.util.ArrayList; + +import betterquesting.api2.client.gui.misc.ComparatorGuiDepth; +import betterquesting.api2.client.gui.misc.IGuiRect; +import betterquesting.api2.client.gui.panels.IGuiPanel; + +public class CanvasScrollingBuffered extends CanvasScrolling { + + private final ArrayList buffer = new ArrayList<>(); + + public CanvasScrollingBuffered(IGuiRect rect) { + super(rect); + } + + public void addPanelToBuffer(IGuiPanel panel) { + if (panel != null) + buffer.add(panel); + } + + public void flushBuffer() { + if (buffer.isEmpty()) + return; + for (IGuiPanel panel : buffer) { + if (guiPanels.contains(panel)) + continue; + + guiPanels.add(panel); + cullingManager.addPanel(panel, true); + panel.initPanel(); + } + buffer.clear(); + + guiPanels.sort(ComparatorGuiDepth.INSTANCE); + + this.refreshScrollBounds(); + } + +} diff --git a/src/main/java/betterquesting/api2/client/gui/panels/lists/CanvasSearch.java b/src/main/java/betterquesting/api2/client/gui/panels/lists/CanvasSearch.java index 42203b2f4..0f93fd666 100644 --- a/src/main/java/betterquesting/api2/client/gui/panels/lists/CanvasSearch.java +++ b/src/main/java/betterquesting/api2/client/gui/panels/lists/CanvasSearch.java @@ -6,7 +6,7 @@ import java.util.*; import java.util.concurrent.TimeUnit; -public abstract class CanvasSearch extends CanvasScrolling { +public abstract class CanvasSearch extends CanvasScrollingBuffered { private String searchTerm = ""; private Iterator searching = null; @@ -39,6 +39,10 @@ public void drawPanel(int mx, int my, float partialTick) { super.drawPanel(mx, my, partialTick); } + public boolean isSearching() { + return searching != null || !pendingResults.isEmpty(); + } + public void refreshSearch() { this.resetCanvas(); this.searchIdx = 0; @@ -71,6 +75,10 @@ private void updateSearch() { savedResults.addAll(tmp); searchTime.stop(); + + if (!searching.hasNext()) + searching = null; + } private void updateResults() { @@ -80,11 +88,16 @@ private void updateResults() { searchTime.reset().start(); - while (!pendingResults.isEmpty() && searchTime.elapsed(TimeUnit.MILLISECONDS) < 100) { - if (addResult(pendingResults.poll(), searchIdx, resultWidth)) searchIdx++; + int count = 0; + while (!pendingResults.isEmpty() && searchTime.elapsed(TimeUnit.MILLISECONDS) < 10 && count < 200) { + if (addResult(pendingResults.poll(), searchIdx, resultWidth)) { + searchIdx++; + count++; + } } searchTime.stop(); + flushBuffer(); } public List getResults() { @@ -96,4 +109,5 @@ public List getResults() { protected abstract void queryMatches(E value, String query, final ArrayDeque results); protected abstract boolean addResult(T entry, int index, int cachedWidth); + } diff --git a/src/main/java/betterquesting/api2/client/gui/resources/textures/RotatingTexture.java b/src/main/java/betterquesting/api2/client/gui/resources/textures/RotatingTexture.java new file mode 100644 index 000000000..0e8857f52 --- /dev/null +++ b/src/main/java/betterquesting/api2/client/gui/resources/textures/RotatingTexture.java @@ -0,0 +1,95 @@ +package betterquesting.api2.client.gui.resources.textures; + +import org.lwjgl.opengl.GL11; + +import betterquesting.api2.client.gui.misc.IGuiRect; +import betterquesting.api2.client.gui.resources.colors.GuiColorStatic; +import betterquesting.api2.client.gui.resources.colors.IGuiColor; +import net.minecraft.client.Minecraft; +import net.minecraft.client.renderer.GlStateManager; +import net.minecraft.util.ResourceLocation; +import net.minecraftforge.fml.client.config.GuiUtils; + +public class RotatingTexture implements IGuiTexture { + + private static final IGuiColor defColor = new GuiColorStatic(255, 255, 255, 255); + + private final ResourceLocation texture; + private final IGuiRect texBounds; + private boolean maintainAspect = false; + private float period; + + public RotatingTexture(ResourceLocation texture, IGuiRect bounds) { + this.texture = texture; + this.texBounds = bounds; + setPeriod(1); + } + + public RotatingTexture maintainAspect(boolean enable) { + this.maintainAspect = enable; + return this; + } + + public void setPeriod(float period) { this.period = period; } + + @Override + public void drawTexture(int x, int y, int width, int height, float zLevel, float partialTick) { + drawTexture(x, y, width, height, zLevel, partialTick, defColor); + } + + @Override + public void drawTexture(int x, int y, int width, int height, float zLevel, float partialTick, IGuiColor color) { + if (width <= 0 || height <= 0) + return; + + GlStateManager.pushMatrix(); + + float sx = (float) width / (float) texBounds.getWidth(); + float sy = (float) height / (float) texBounds.getHeight(); + + if (maintainAspect) { + float sa = Math.min(sx, sy); + float dx = (sx - sa) * texBounds.getWidth() / 2F; + float dy = (sy - sa) * texBounds.getHeight() / 2F; + sx = sa; + sy = sa; + GlStateManager.translate(x + dx, y + dy, 0F); + } else { + GlStateManager.translate(x, y, 0F); + } + + GlStateManager.scale(sx, sy, 1F); + float w2 = texBounds.getWidth() * 0.5f; + float h2 = texBounds.getHeight() * 0.5f; + GlStateManager.translate(w2, h2, 0); + GlStateManager.rotate(getAngle(period), 0, 0, 1); + GlStateManager.translate(-w2, -h2, 0); + color.applyGlColor(); + + GlStateManager.enableBlend(); + GlStateManager.tryBlendFuncSeparate(GL11.GL_SRC_ALPHA, GL11.GL_ONE_MINUS_SRC_ALPHA, 1, 0); + + Minecraft.getMinecraft().renderEngine.bindTexture(texture); + GuiUtils.drawTexturedModalRect(0, 0, texBounds.getX(), texBounds.getY(), texBounds.getWidth(), texBounds.getHeight(), zLevel); + + GlStateManager.popMatrix(); + } + + @Override + public ResourceLocation getTexture() { return this.texture; } + + @Override + public IGuiRect getBounds() { return this.texBounds; } + + private static float getAngle(float period) { + float phase = 0; + // Period in milliseconds + double pms = 1000D * period; + // Current period time + double time = System.currentTimeMillis() % pms; + // Shift current time by phase, wrap value and scale between 0.0 - 1.0 + time = (time + (pms * phase)) % pms / pms; + return (float) time * 360; + } + +} diff --git a/src/main/java/betterquesting/api2/client/gui/themes/presets/PresetIcon.java b/src/main/java/betterquesting/api2/client/gui/themes/presets/PresetIcon.java index f91329277..4b7fbb0e4 100644 --- a/src/main/java/betterquesting/api2/client/gui/themes/presets/PresetIcon.java +++ b/src/main/java/betterquesting/api2/client/gui/themes/presets/PresetIcon.java @@ -2,6 +2,7 @@ import betterquesting.api2.client.gui.misc.GuiRectangle; import betterquesting.api2.client.gui.resources.textures.IGuiTexture; +import betterquesting.api2.client.gui.resources.textures.RotatingTexture; import betterquesting.api2.client.gui.resources.textures.SimpleTexture; import betterquesting.api2.client.gui.themes.IThemeRegistry; import betterquesting.client.themes.ThemeRegistry; @@ -99,7 +100,8 @@ public enum PresetIcon { ICON_MENU("icon_menu"), ICON_PATREON("icon_patreon"), - ICON_TWITCH("icon_twitch"); + ICON_TWITCH("icon_twitch"), + ICON_LOADING("icon_loading"); public static final ResourceLocation TX_ICONS = new ResourceLocation(ModReference.MODID, "textures/gui/editor_icons.png"); @@ -197,5 +199,6 @@ public static void registerIcons(IThemeRegistry reg) { reg.setDefaultTexture(ICON_PATREON.key, new SimpleTexture(TX_ICONS, new GuiRectangle(144, 80, 16, 16)).maintainAspect(true)); reg.setDefaultTexture(ICON_TWITCH.key, new SimpleTexture(TX_ICONS, new GuiRectangle(160, 80, 16, 16)).maintainAspect(true)); + reg.setDefaultTexture(ICON_LOADING.key, new RotatingTexture(TX_ICONS, new GuiRectangle(128, 16, 16, 16)).maintainAspect(true)); } } diff --git a/src/main/java/betterquesting/client/gui2/editors/GuiQuestLineAddRemove.java b/src/main/java/betterquesting/client/gui2/editors/GuiQuestLineAddRemove.java index e2e5b0d62..733474828 100644 --- a/src/main/java/betterquesting/client/gui2/editors/GuiQuestLineAddRemove.java +++ b/src/main/java/betterquesting/client/gui2/editors/GuiQuestLineAddRemove.java @@ -20,10 +20,12 @@ import betterquesting.api2.client.gui.panels.CanvasEmpty; import betterquesting.api2.client.gui.panels.CanvasTextured; import betterquesting.api2.client.gui.panels.bars.PanelVScrollBar; +import betterquesting.api2.client.gui.panels.content.PanelGeneric; import betterquesting.api2.client.gui.panels.content.PanelLine; import betterquesting.api2.client.gui.panels.content.PanelTextBox; import betterquesting.api2.client.gui.panels.lists.CanvasQuestDatabase; import betterquesting.api2.client.gui.panels.lists.CanvasScrolling; +import betterquesting.api2.client.gui.resources.colors.GuiColorStatic; import betterquesting.api2.client.gui.themes.presets.PresetColor; import betterquesting.api2.client.gui.themes.presets.PresetIcon; import betterquesting.api2.client.gui.themes.presets.PresetLine; @@ -45,12 +47,14 @@ import java.util.List; public class GuiQuestLineAddRemove extends GuiScreenCanvas implements IPEventListener, IVolatileScreen, INeedsRefresh { + @Nullable private IQuestLine questLine; private final int lineID; private CanvasQuestDatabase canvasDB; private CanvasScrolling canvasQL; + private PanelGeneric pnLoading; public GuiQuestLineAddRemove(GuiScreen parent, @Nullable IQuestLine questLine) { super(parent); @@ -107,28 +111,34 @@ public void initPanel() { PanelTextBox txtDb = new PanelTextBox(new GuiTransform(GuiAlign.TOP_EDGE, new GuiPadding(0, 0, 0, -16), 0), QuestTranslation.translate("betterquesting.gui.database")).setAlignment(1).setColor(PresetColor.TEXT_MAIN.getColor()); cvRight.addPanel(txtDb); - PanelTextField searchBox = new PanelTextField<>(new GuiTransform(GuiAlign.TOP_EDGE, new GuiPadding(0, 16, 8, -32), 0), "", FieldFilterString.INSTANCE); + PanelTextField searchBox = new PanelTextField<>(new GuiTransform(GuiAlign.TOP_EDGE, new GuiPadding(0, 16, 24, -32), 0), "", FieldFilterString.INSTANCE); searchBox.setWatermark("Search..."); cvRight.addPanel(searchBox); + pnLoading = new PanelGeneric(new GuiTransform(GuiAlign.TOP_RIGHT, new GuiPadding(-24, 16, 8, -32), 0), PresetIcon.ICON_LOADING.getTexture(), new GuiColorStatic(0, 255, 0, 255)); + pnLoading.setEnabled(false); + cvRight.addPanel(pnLoading); + canvasDB = new CanvasQuestDatabase(new GuiTransform(GuiAlign.FULL_BOX, new GuiPadding(0, 32, 8, 24), 0)) { + @Override protected boolean addResult(DBEntry entry, int index, int width) { PanelButtonStorage> btnAdd = new PanelButtonStorage<>(new GuiRectangle(0, index * 16, 16, 16, 0), 2, "", entry); btnAdd.setIcon(PresetIcon.ICON_POSITIVE.getTexture()); btnAdd.setActive(questLine != null && questLine.getValue(entry.getID()) == null); - this.addPanel(btnAdd); + this.addPanelToBuffer(btnAdd); PanelButtonStorage> btnEdit = new PanelButtonStorage<>(new GuiRectangle(16, index * 16, width - 32, 16, 0), 1, QuestTranslation.translate(entry.getValue().getProperty(NativeProps.NAME)), entry); - this.addPanel(btnEdit); + this.addPanelToBuffer(btnEdit); PanelButtonStorage> btnDel = new PanelButtonStorage<>(new GuiRectangle(width - 16, index * 16, 16, 16, 0), 4, "", entry); btnDel.setIcon(PresetIcon.ICON_TRASH.getTexture()); - this.addPanel(btnDel); + this.addPanelToBuffer(btnDel); return true; } + }; cvRight.addPanel(canvasDB); @@ -153,6 +163,12 @@ protected boolean addResult(DBEntry entry, int index, int width) { refreshQuestList(); } + @Override + public void drawPanel(int mx, int my, float partialTick) { + pnLoading.setEnabled(canvasDB.isSearching()); + super.drawPanel(mx, my, partialTick); + } + @Override public void onPanelEvent(PanelEvent event) { if (event instanceof PEventButton) { @@ -273,4 +289,5 @@ private void SendChanges() { payload.setInteger("action", 0); NetChapterEdit.sendEdit(payload); } + }