1414import lombok .var ;
1515import org .jetbrains .annotations .NotNull ;
1616import org .jetbrains .annotations .Nullable ;
17+ import org .jspecify .annotations .NullMarked ;
1718
1819import java .util .List ;
1920
@@ -67,9 +68,17 @@ public GuiImmediateContext getImmContext(
6768 );
6869 }
6970
71+ @ NullMarked
7072 public class EditorComponentWrapper extends PanelComponent {
73+ public final @ Nullable GuiComponent bottomComponent ;
74+
7175 public EditorComponentWrapper (GuiComponent component ) {
76+ this (component , null );
77+ }
78+
79+ public EditorComponentWrapper (GuiComponent component , @ Nullable GuiComponent bottomComponent ) {
7280 super (component );
81+ this .bottomComponent = bottomComponent ;
7382 }
7483
7584 @ Override
@@ -84,74 +93,124 @@ protected int getDescriptionHeight() {
8493 return Math .max (45 , fr .splitText (option .getDescription (), 250 * 2 / 3 - 10 ).size () * (fr .getHeight () + 1 ) + 10 );
8594 }
8695
87- @ Override
88- public int getHeight () {
96+ public int getTopHeight () {
8997 int height = getDescriptionHeight ();
90- if (option .getConfig ().getTitleRenderingBehaviour (option ) == TitleRenderingBehaviour .WIDE_CENTERED )
98+ if (option .getConfig ().getTitleRenderingBehaviour (option ) != TitleRenderingBehaviour .LEFT )
9199 height += IMinecraft .INSTANCE .getDefaultFontRenderer ().getHeight () + 1 ;
92- return height ;
100+ return Math .max (HEIGHT , height );
101+ }
102+
103+ @ Override
104+ public int getHeight () {
105+ return getTopHeight () + (bottomComponent != null ? bottomComponent .getHeight () + 10 : 0 );
93106 }
94107
95108 @ Override
96109 protected GuiImmediateContext getChildContext (GuiImmediateContext context ) {
97- return context .translated (5 , 13 , context .getWidth () / 3 - 10 , context .getHeight () - 13 );
110+ return context .translated (5 , 15 , context .getWidth () / 3 - 10 , context .getHeight () - 15 );
98111 }
99112
113+ protected int getEffectiveTopHeight (GuiImmediateContext context ) {
114+ return Math .min (context .getHeight (), (getTopHeight ()));
115+ }
116+
117+ protected GuiImmediateContext getBottomContext (GuiImmediateContext context ) {
118+ int effectiveTopHeight = getEffectiveTopHeight (context );
119+ return context .translated (5 , effectiveTopHeight + bottomOffset , context .getWidth () - 10 , context .getHeight () - effectiveTopHeight - bottomOffset - 8 );
120+ }
121+
122+ protected GuiImmediateContext getTopContext (GuiImmediateContext context ) {
123+ return context .translated (0 , 0 , context .getWidth (), getEffectiveTopHeight (context ));
124+ }
125+
126+ int bottomOffset = 0 ;
127+
100128 @ Override
101- public void render (@ NotNull GuiImmediateContext context ) {
129+ public void render (GuiImmediateContext context ) {
102130 context .getRenderContext ().drawDarkRect (0 , 0 , context .getWidth (), context .getHeight () - 2 );
103131
104- renderTitle (context );
132+ var topContext = getTopContext (context );
133+ renderTitle (topContext );
105134
106- renderDescription (context );
135+ renderDescription (topContext );
107136
108- renderElement (context );
137+ renderElement (topContext );
138+
139+ context .getRenderContext ().pushMatrix ();
140+ context .getRenderContext ().translate (5 , getEffectiveTopHeight (context ) + bottomOffset );
141+ renderBottomElement (getBottomContext (context ));
142+ context .getRenderContext ().popMatrix ();
143+ }
144+
145+ protected void renderBottomElement (GuiImmediateContext context ) {
146+ if (bottomComponent != null )
147+ bottomComponent .render (context );
109148 }
110149
111- protected void renderElement (@ NotNull GuiImmediateContext context ) {
150+ protected void renderElement (GuiImmediateContext context ) {
112151 context .getRenderContext ().pushMatrix ();
113- context .getRenderContext ().translate (5 , 13 );
152+ context .getRenderContext ().translate (5 , 15 );
114153 this .getElement ().render (getChildContext (context ));
115154 context .getRenderContext ().popMatrix ();
116155 }
117156
118- protected void renderTitle (@ NotNull GuiImmediateContext context ) {
157+ protected void renderTitle (GuiImmediateContext context ) {
119158 int width = context .getWidth ();
120159 var minecraft = context .getRenderContext ().getMinecraft ();
121160 var fr = minecraft .getDefaultFontRenderer ();
122161 switch (option .getConfig ().getTitleRenderingBehaviour (option )) {
162+ case WIDE_CENTERED_UNDERLINED :
163+ context .getRenderContext ().drawHorizontalLine (16 , 10 , width - 10 , 0xFF404040 );
164+ // fallthrough;
123165 case WIDE_CENTERED :
124166 context .getRenderContext ().drawStringCenteredScaledMaxWidth (
125- option .getName (), fr , width / 2 , 13 , true , width - 10 , 0xe0e0e0
167+ option .getName (), fr , width / 2 , 10 , true , width - 10 , 0xe0e0e0
126168 );
127169 break ;
128170 case LEFT :
129171 context .getRenderContext ().drawStringCenteredScaledMaxWidth (
130- option .getName (), fr , width / 6 , 13 , true , width / 3 - 10 , 0xe0e0e0
172+ option .getName (), fr , width / 6 , 10 , true , width / 3 - 10 , 0xe0e0e0
131173 );
132174 break ;
133175 }
134176 }
135177
178+ @ Override
179+ public boolean mouseEvent (MouseEvent mouseEvent , GuiImmediateContext context ) {
180+ if (super .mouseEvent (mouseEvent , getTopContext (context )))
181+ return true ;
182+ if (bottomComponent != null && bottomComponent .mouseEvent (mouseEvent , getBottomContext (context )))
183+ return true ;
184+ return false ;
185+ }
186+
187+ @ Override
188+ public boolean keyboardEvent (KeyboardEvent event , GuiImmediateContext context ) {
189+ if (super .keyboardEvent (event , getTopContext (context )))
190+ return true ;
191+ if (bottomComponent != null && bottomComponent .keyboardEvent (event , getBottomContext (context )))
192+ return true ;
193+ return false ;
194+ }
195+
136196 protected void renderDescription (@ NotNull GuiImmediateContext context ) {
137197 int width = context .getWidth ();
138198 var minecraft = context .getRenderContext ().getMinecraft ();
139199 var fr = minecraft .getDefaultFontRenderer ();
140- int yOffset = option .getConfig ().getTitleRenderingBehaviour (option ) == TitleRenderingBehaviour .WIDE_CENTERED ? fr .getHeight () + 1 : 5 ;
200+ int yOffset = option .getConfig ().getTitleRenderingBehaviour (option ) != TitleRenderingBehaviour .LEFT ? fr .getHeight () + 13 : 5 ;
141201 float scale = 1 ;
142202 List <StructuredText > lines ;
143- int descriptionHeight = ( option . getConfig (). getDescriptionBehaviour ( option ) != DescriptionRendereringBehaviour . EXPAND_PANEL ? HEIGHT : context .getHeight () ) - yOffset ;
203+ int descriptionHeight = context .getHeight () - yOffset ;
144204 while (true ) {
145205 lines = fr .splitText (option .getDescription (), (int ) (width * 2 / 3 / scale - 10 ));
146- if (lines .size () * scale * (fr .getHeight () + 1 ) + 10 < descriptionHeight )
206+ if (lines .size () * scale * (fr .getHeight () + 1 ) < descriptionHeight )
147207 break ;
148208 scale -= 1 / 8f ;
149209 if (scale < 1 / 16f ) break ;
150210 }
151211 context .getRenderContext ().pushMatrix ();
152212 context .getRenderContext ().translate (5 + width / 3 , yOffset );
153213 context .getRenderContext ().scale (scale , scale );
154- context .getRenderContext ().translate (0 , ((descriptionHeight - 10 ) - (fr .getHeight () + 1 ) * (lines .size () - 1 ) * scale ) / 2F );
155214 for (var line : lines ) {
156215 context .getRenderContext ().drawString (fr , line , 0 , 0 , 0xc0c0c0 , false );
157216 context .getRenderContext ().translate (0 , fr .getHeight () + 1 );
@@ -160,6 +219,13 @@ protected void renderDescription(@NotNull GuiImmediateContext context) {
160219 }
161220 }
162221
222+ protected GuiComponent wrapComponent (GuiComponent component , @ Nullable GuiComponent bottomComponent ) {
223+ return new EditorComponentWrapper (
224+ new CenterComponent (component ),
225+ bottomComponent
226+ );
227+ }
228+
163229 protected GuiComponent wrapComponent (GuiComponent component ) {
164230 return new EditorComponentWrapper (
165231 new CenterComponent (component )
0 commit comments