2121import com .cleanroommc .modularui .api .drawable .IDrawable ;
2222import com .cleanroommc .modularui .api .drawable .IKey ;
2323import com .cleanroommc .modularui .api .widget .IWidget ;
24+ import com .cleanroommc .modularui .drawable .keys .DynamicKey ;
2425import com .cleanroommc .modularui .factory .PosGuiData ;
2526import com .cleanroommc .modularui .screen .ModularPanel ;
2627import com .cleanroommc .modularui .utils .Alignment ;
3536import com .cleanroommc .modularui .widgets .CycleButtonWidget ;
3637import com .cleanroommc .modularui .widgets .ProgressWidget ;
3738import com .cleanroommc .modularui .widgets .SlotGroupWidget ;
38- import com .cleanroommc .modularui .widgets .TextWidget ;
3939import com .cleanroommc .modularui .widgets .layout .Column ;
4040import com .cleanroommc .modularui .widgets .layout .Row ;
41+ import it .unimi .dsi .fastutil .ints .Int2ObjectArrayMap ;
42+ import it .unimi .dsi .fastutil .ints .Int2ObjectMap ;
4143import org .jetbrains .annotations .NotNull ;
4244import org .jetbrains .annotations .Nullable ;
4345
4446import java .io .IOException ;
4547import java .util .ArrayList ;
48+ import java .util .Collections ;
4649import java .util .List ;
4750import java .util .function .BiFunction ;
4851import java .util .function .BooleanSupplier ;
@@ -114,12 +117,10 @@ public void readInitialSync(PacketBuffer buffer) {
114117 this .valueSyncer .accept (panelSyncManager );
115118 var panel = createRootPanel ();
116119
117- var displayText = new ArrayList <Widget <?>>();
118-
119120 // TODO createExtras() hook for overrides?
120121 var bars = createBars (panel , panelSyncManager );
121122
122- return panel .child (createScreen (displayText , panelSyncManager ))
123+ return panel .child (createScreen (panelSyncManager ))
123124 .childIf (bars != null , bars )
124125 .child (new Row ()
125126 .bottom (7 )
@@ -131,18 +132,12 @@ public void readInitialSync(PacketBuffer buffer) {
131132 }
132133
133134 private Widget <?> createIndicator () {
134- List <Widget <?>> textList = new ArrayList <>();
135- var builder = builder (textList );
135+ var builder = builder ();
136136 return new Widget <>()
137137 .pos (174 - 5 , 93 - 5 )
138138 .onUpdateListener (w -> w .overlay (getIndicatorOverlay (builder )))
139139 .tooltip (tooltip -> tooltip .setAutoUpdate (true ))
140- .tooltipBuilder (tooltip -> {
141- for (var text : textList ) {
142- if (text instanceof TextWidget textWidget )
143- tooltip .addLine (textWidget .getKey ());
144- }
145- });
140+ .tooltipBuilder (tooltip -> tooltip .addDrawableLines (builder .getTextList ()));
146141 }
147142
148143 private IDrawable getIndicatorOverlay (Builder builder ) {
@@ -287,25 +282,27 @@ protected Column createBars(@NotNull ModularPanel mainPanel,
287282 return column ;
288283 }
289284
290- protected Widget <?> createScreen (List <Widget <?>> lines , PanelSyncManager syncManager ) {
291- final var builder = builder (lines );
285+ protected Widget <?> createScreen (PanelSyncManager syncManager ) {
286+ final var builder = builder ();
287+ this .displayText .accept (builder );
288+ var col = new Column ();
289+ builder .build (col );
290+
292291 return new ParentWidget <>()
293292 .child (createIndicator ())
294293 .child (new ScrollWidget <>(new VerticalScrollData ())
295294 .sizeRel (1f )
296- .child (new Column ()
297- .expanded ( )
295+ .child (col . expanded ()
296+ .margin ( 4 , 4 )
298297 .onUpdateListener (column -> {
299- int prev = lines .size ();
300- builder .clear ();
301- this .displayText .accept (builder );
302- if (prev == lines .size ()) return ;
298+ var b = builder ();
299+ this .displayText .accept (b );
300+ if (!builder .hasChanged (b )) return ;
303301 column .getChildren ().clear ();
304302 // really debating on if the display screen should be its own widget
305- lines . forEach (column :: child );
303+ b . build (column );
306304 resize (column );
307- })
308- .margin (4 , 4 )))
305+ })))
309306 .background (GTGuiTextures .DISPLAY )
310307 .size (190 , 109 )
311308 .pos (4 , 4 );
@@ -422,15 +419,16 @@ public static final class Bars {
422419 private Bars () {}
423420 }
424421
425- protected static Builder builder (List < Widget <?>> list ) {
426- return new Builder (list );
422+ protected static Builder builder () {
423+ return new Builder ();
427424 }
428425
429426 @ SuppressWarnings ({ "UnusedReturnValue" , "unused" })
430427 public static class Builder {
431428
432- private final List <Widget <?>> textList ;
433- private Function <IKey , Widget <?>> widgetFunction = Builder ::keyMapper ;
429+ private final List <IDrawable > textList ;
430+ private Function <IDrawable , Widget <?>> widgetFunction = Builder ::keyMapper ;
431+ private final Int2ObjectMap <IDrawable > tooltips = new Int2ObjectArrayMap <>();
434432
435433 private BooleanSupplier isWorkingEnabled = () -> false ;
436434 private BooleanSupplier isActive = () -> false ;
@@ -441,14 +439,14 @@ public static class Builder {
441439 private IKey pausedKey = IKey .lang ("gregtech.multiblock.work_paused" );
442440 private IKey runningKey = IKey .lang ("gregtech.multiblock.running" );
443441
444- protected static Widget <?> keyMapper (IKey key ) {
442+ protected static Widget <?> keyMapper (IDrawable key ) {
445443 return key .asWidget ()
446444 .widthRel (1f )
447445 .height (12 );
448446 }
449447
450- private Builder (List < Widget <?>> textList ) {
451- this .textList = textList ;
448+ private Builder () {
449+ this .textList = new ArrayList <>() ;
452450 }
453451
454452 public Builder structureFormed (boolean structureFormed ) {
@@ -457,7 +455,7 @@ public Builder structureFormed(boolean structureFormed) {
457455 var base = KeyUtil .lang (TextFormatting .RED , "gregtech.multiblock.invalid_structure" );
458456 var hover = KeyUtil .lang (TextFormatting .GRAY ,
459457 "gregtech.multiblock.invalid_structure.tooltip" );
460- addKey (base ). addTooltipLine ( hover );
458+ addKey (base , hover );
461459 }
462460 return this ;
463461 }
@@ -510,7 +508,7 @@ public Builder addEnergyUsageLine(IEnergyContainer energyContainer) {
510508 "gregtech.multiblock.max_energy_per_tick" , energyFormatted , voltageName );
511509 var hoverText = KeyUtil .lang (TextFormatting .GRAY ,
512510 "gregtech.multiblock.max_energy_per_tick_hover" );
513- addKey (bodyText ). addTooltipLine ( hoverText );
511+ addKey (bodyText , hoverText );
514512 }
515513 return this ;
516514 }
@@ -529,7 +527,7 @@ public Builder addEnergyTierLine(int tier) {
529527 "gregtech.multiblock.max_recipe_tier" , GTValues .VNF [tier ]);
530528 var hoverText = KeyUtil .lang (TextFormatting .GRAY ,
531529 "gregtech.multiblock.max_recipe_tier_hover" );
532- addKey (bodyText ). addTooltipLine ( hoverText );
530+ addKey (bodyText , hoverText );
533531 return this ;
534532 }
535533
@@ -848,8 +846,8 @@ public Builder addEmptyLine() {
848846 }
849847
850848 /** Add custom text dynamically, allowing for custom application logic. */
851- public Builder addCustom (Consumer <List <IKey >> customConsumer ) {
852- List <IKey > customKeys = new ArrayList <>();
849+ public Builder addCustom (Consumer <List <IDrawable >> customConsumer ) {
850+ List <IDrawable > customKeys = new ArrayList <>();
853851 customConsumer .accept (customKeys );
854852 customKeys .forEach (this ::addKey );
855853 return this ;
@@ -858,7 +856,7 @@ public Builder addCustom(Consumer<List<IKey>> customConsumer) {
858856 /**
859857 * @param widgetFunction function to build widgets from keys
860858 */
861- public Builder widgetFunction (Function <IKey , Widget <?>> widgetFunction ) {
859+ public Builder widgetFunction (Function <IDrawable , Widget <?>> widgetFunction ) {
862860 this .widgetFunction = widgetFunction ;
863861 return this ;
864862 }
@@ -871,10 +869,41 @@ protected void clear() {
871869 textList .clear ();
872870 }
873871
874- private Widget <?> addKey (IKey key ) {
875- var w = this .widgetFunction .apply (key );
876- this .textList .add (w );
877- return w ;
872+ protected void build (ParentWidget <?> parent ) {
873+ for (int i = 0 ; i < textList .size (); i ++) {
874+ var line = this .widgetFunction .apply (textList .get (i ));
875+ if (tooltips .containsKey (i ))
876+ line .addTooltipLine (tooltips .get (i ));
877+ parent .child (line );
878+ }
879+ }
880+
881+ protected List <IDrawable > getTextList () {
882+ return Collections .unmodifiableList (textList );
883+ }
884+
885+ protected boolean hasChanged (Builder other ) {
886+ if (textList .size () != other .textList .size ()) return true ;
887+ for (int i = 0 ; i < textList .size (); i ++) {
888+ IDrawable left = textList .get (i ), right = other .textList .get (i );
889+
890+ // dynamic keys are impossible to check, skip
891+ if (left instanceof DynamicKey && right instanceof DynamicKey )
892+ continue ;
893+
894+ if (!left .equals (right ))
895+ return true ;
896+ }
897+ return false ;
898+ }
899+
900+ private void addKey (IDrawable key ) {
901+ this .textList .add (key );
902+ }
903+
904+ private void addKey (IDrawable key , IDrawable hover ) {
905+ this .tooltips .put (textList .size (), hover );
906+ addKey (key );
878907 }
879908 }
880909}
0 commit comments