1- using System ;
21using C7GameData ;
32using ConvertCiv3Media ;
43using Godot ;
5- using Serilog ;
6- using Serilog . Events ;
74
85namespace C7 . Map {
96 public partial class CityLabelScene : Node2D {
10- private ILogger log = LogManager . ForContext < CityLabelScene > ( ) ;
11-
12- private City city ;
13- private Tile tile ;
14- private Vector2I tileCenter ;
15-
16- private ImageTexture cityTexture ;
7+ City city ;
8+ Vector2I tileCenter ;
9+ Color civColor ;
1710
11+ const byte TRANSPARENCY = 192 ; // 25%
1812 const int CITY_LABEL_HEIGHT = 23 ;
1913 const int LEFT_RIGHT_BOXES_WIDTH = 24 ;
2014 const int LEFT_RIGHT_BOXES_HEIGHT = CITY_LABEL_HEIGHT - 2 ;
21- const int TEXT_ROW_HEIGHT = 9 ;
15+ const int CENTRAL_PANEL_SEPARATOR_WIDTH = 4 ;
16+
17+ static Pcx cityIcons = Util . LoadPCX ( "Art/Cities/city icons.pcx" ) ;
18+ static Image nonEmbassyStar ;
19+ static Theme smallFontTheme = new ( ) ;
20+ static Theme popThemeRed = new ( ) ;
21+ static Theme popSizeTheme = new ( ) ;
2222
23- ImageTexture cityLabel = new ImageTexture ( ) ;
23+ PanelContainer labelPanel = new ( ) ;
24+ HBoxContainer mainContainer = new ( ) ;
25+ PanelContainer popSizePanel = new ( ) ;
26+ VBoxContainer centerContainer = new ( ) ;
27+ PanelContainer capitalPanel = new ( ) ;
28+ HSeparator centerDivider = new ( ) ;
2429
25- private TextureRect labelTextureRect = new TextureRect ( ) ;
26- Label cityNameLabel = new Label ( ) ;
27- Label productionLabel = new Label ( ) ;
28- Label popSizeLabel = new Label ( ) ;
30+ HSeparator borderTop = new ( ) ;
31+ HSeparator borderBottom = new ( ) ;
2932
30- private static FontFile smallFont = new FontFile ( ) ;
31- private static FontFile midSizedFont = new FontFile ( ) ;
33+ VSeparator leftSeparator = new ( ) ;
34+ VSeparator rightSeparator = new ( ) ;
3235
33- private static Pcx cityIcons = Util . LoadPCX ( "Art/Cities/city icons.pcx" ) ;
34- private static Image nonEmbassyStar ;
35- private static Theme smallFontTheme = new Theme ( ) ;
36- private static Theme popThemeRed = new Theme ( ) ;
37- private static Theme popSizeTheme = new Theme ( ) ;
36+ Label cityNameLabel = new ( ) ;
37+ Label productionLabel = new ( ) ;
38+ Label popSizeLabel = new ( ) ;
3839
39- private int lastLabelWidth = 0 ;
40+ static FontFile smallFont = new ( ) ;
41+ static FontFile midSizedFont = new ( ) ;
42+
43+ Color topRowGrey = Color . Color8 ( 32 , 32 , 32 , TRANSPARENCY ) ;
44+ Color bottomRowGrey = Color . Color8 ( 48 , 48 , 48 , TRANSPARENCY ) ;
45+ Color backgroundGrey = Color . Color8 ( 64 , 64 , 64 , TRANSPARENCY ) ;
46+ Color borderGrey = Color . Color8 ( 80 , 80 , 80 , TRANSPARENCY ) ;
4047
4148 static CityLabelScene ( ) {
4249 smallFontTheme . DefaultFont = smallFont ;
@@ -60,144 +67,161 @@ static CityLabelScene() {
6067 nonEmbassyStar = PCXToGodot . getImageFromPCX ( cityIcons , new ( 20 , 1 , 18 , 18 ) ) ;
6168 }
6269
63- public CityLabelScene ( City city , Tile tile , Vector2I tileCenter ) {
70+ public CityLabelScene ( City city , Vector2I tileCenter ) {
6471 this . city = city ;
65- this . tile = tile ;
6672 this . tileCenter = tileCenter ;
6773
74+ civColor = new Color ( Util . LoadColor ( city . owner . colorIndex ) , TRANSPARENCY ) ;
6875
69- labelTextureRect . MouseFilter = Control . MouseFilterEnum . Ignore ;
70- cityNameLabel . MouseFilter = Control . MouseFilterEnum . Ignore ;
71- productionLabel . MouseFilter = Control . MouseFilterEnum . Ignore ;
72- popSizeLabel . MouseFilter = Control . MouseFilterEnum . Ignore ;
76+ // Set up UI hierarchy
77+ AddChild ( labelPanel ) ;
78+ labelPanel . AddChild ( mainContainer ) ;
7379
74- AddChild ( labelTextureRect ) ;
75- AddChild ( cityNameLabel ) ;
76- AddChild ( productionLabel ) ;
77- AddChild ( popSizeLabel ) ;
78- }
80+ // Left side (population)
81+ mainContainer . AddChild ( popSizePanel ) ;
82+ popSizePanel . AddChild ( popSizeLabel ) ;
7983
80- public override void _Draw ( ) {
81- base . _Draw ( ) ;
84+ // Center (city name, production and population growth)
85+ mainContainer . AddChild ( leftSeparator ) ;
86+ mainContainer . AddChild ( centerContainer ) ;
87+ mainContainer . AddChild ( rightSeparator ) ;
88+ SetupCenterPanel ( ) ;
8289
83- int turnsUntilGrowth = city . TurnsUntilGrowth ( ) ;
84- string turnsUntilGrowthText = turnsUntilGrowth == int . MaxValue || turnsUntilGrowth < 0 ? "- -" : "" + turnsUntilGrowth ;
85- string cityNameAndGrowth = $ "{ city . name } : { turnsUntilGrowthText } ";
86- string productionDescription = city . itemBeingProduced . name + " : " + city . TurnsUntilProductionFinished ( ) ;
87-
88- int cityNameAndGrowthWidth = ( int ) smallFont . GetStringSize ( cityNameAndGrowth ) . X ;
89- int productionDescriptionWidth = ( int ) smallFont . GetStringSize ( productionDescription ) . X ;
90- int maxTextWidth = Math . Max ( cityNameAndGrowthWidth , productionDescriptionWidth ) ;
91-
92- int cityLabelWidth = maxTextWidth + ( city . IsCapital ( ) ? 70 : 45 ) ; //TODO: Is 65 right? 70? Will depend on whether it's capital, too
93- int textAreaWidth = cityLabelWidth - ( city . IsCapital ( ) ? 50 : 25 ) ;
94- if ( log . IsEnabled ( LogEventLevel . Verbose ) ) {
95- log . Verbose ( "Width of city name = " + maxTextWidth ) ;
96- log . Verbose ( "City label width: " + cityLabelWidth ) ;
97- log . Verbose ( "Text area width: " + textAreaWidth ) ;
98- }
90+ mainContainer . AddThemeConstantOverride ( "separation" , 0 ) ;
91+ centerContainer . AddThemeConstantOverride ( "separation" , 0 ) ;
9992
100- if ( cityLabelWidth != lastLabelWidth ) {
101- Image labelBackground = CreateLabelBackground ( cityLabelWidth , city , textAreaWidth ) ;
102- cityLabel = ImageTexture . CreateFromImage ( labelBackground ) ;
103- lastLabelWidth = cityLabelWidth ;
104- }
93+ borderTop . AddThemeConstantOverride ( "separation" , 1 ) ;
94+ borderBottom . AddThemeConstantOverride ( "separation" , 1 ) ;
95+ centerDivider . AddThemeConstantOverride ( "separation" , 1 ) ;
96+
97+ popSizeLabel . HorizontalAlignment = HorizontalAlignment . Center ;
98+ popSizeLabel . VerticalAlignment = VerticalAlignment . Center ;
99+ popSizePanel . CustomMinimumSize = new Vector2 ( LEFT_RIGHT_BOXES_WIDTH , LEFT_RIGHT_BOXES_HEIGHT ) ;
100+
101+ labelPanel . MouseFilter = Control . MouseFilterEnum . Ignore ;
105102
106- DrawLabelOnScreen ( tileCenter , cityLabelWidth , city , cityLabel ) ;
107- DrawTextOnLabel ( tileCenter , cityNameAndGrowthWidth , productionDescriptionWidth , city , cityNameAndGrowth , productionDescription , cityLabelWidth ) ;
103+ cityNameLabel . Theme = smallFontTheme ;
104+ productionLabel . Theme = smallFontTheme ;
105+ popSizeLabel . Theme = popSizeTheme ;
106+
107+ ApplyStyles ( ) ;
108108 }
109109
110- private void DrawLabelOnScreen ( Vector2I tileCenter , int cityLabelWidth , City city , ImageTexture cityLabel ) {
111- labelTextureRect . OffsetLeft = tileCenter . X + ( cityLabelWidth / - 2 ) ;
112- labelTextureRect . OffsetTop = tileCenter . Y + 24 ;
113- labelTextureRect . Texture = cityLabel ;
110+ private void SetupCenterPanel ( ) {
111+ centerContainer . AddChild ( borderTop ) ;
112+ centerContainer . AddChild ( cityNameLabel ) ;
113+ centerContainer . AddChild ( centerDivider ) ;
114+ centerContainer . AddChild ( productionLabel ) ;
115+ centerContainer . AddChild ( borderBottom ) ;
116+
117+ centerContainer . CustomMinimumSize = new Vector2 ( 60 , - 1 ) ;
118+
119+ cityNameLabel . HorizontalAlignment = HorizontalAlignment . Center ;
120+ cityNameLabel . VerticalAlignment = VerticalAlignment . Center ;
121+
122+ productionLabel . HorizontalAlignment = HorizontalAlignment . Center ;
123+ productionLabel . VerticalAlignment = VerticalAlignment . Center ;
114124 }
115125
116- private void DrawTextOnLabel ( Vector2I tileCenter , int cityNameAndGrowthWidth , int productionDescriptionWidth , City city , string cityNameAndGrowth , string productionDescription , int cityLabelWidth ) {
126+ private void SetupCapitalPanel ( ) {
127+ capitalPanel = new PanelContainer ( ) ;
117128
118- //Destination for font is based on lower-left of baseline of font, not upper left as for blitted rectangles
119- int cityNameOffset = cityNameAndGrowthWidth / - 2 ;
120- int prodDescriptionOffset = productionDescriptionWidth / - 2 ;
121- if ( ! city . IsCapital ( ) ) {
122- cityNameOffset += 12 ;
123- prodDescriptionOffset += 12 ;
124- }
129+ StyleBoxFlat capitalStyle = new ( ) {
130+ BgColor = civColor
131+ } ;
125132
126- cityNameLabel . Theme = smallFontTheme ;
127- cityNameLabel . Text = cityNameAndGrowth ;
128- cityNameLabel . OffsetLeft = tileCenter . X + cityNameOffset ;
129- cityNameLabel . OffsetTop = tileCenter . Y + 22 ;
133+ capitalPanel . AddThemeStyleboxOverride ( "panel" , capitalStyle ) ;
134+ capitalPanel . CustomMinimumSize = new Vector2 ( LEFT_RIGHT_BOXES_WIDTH , LEFT_RIGHT_BOXES_HEIGHT ) ;
130135
131- productionLabel . Theme = smallFontTheme ;
132- productionLabel . Text = productionDescription ;
133- productionLabel . OffsetLeft = tileCenter . X + prodDescriptionOffset ;
134- productionLabel . OffsetTop = tileCenter . Y + 32 ;
136+ TextureRect starTextureRect = new ( ) {
137+ Texture = ImageTexture . CreateFromImage ( nonEmbassyStar ) ,
138+ StretchMode = TextureRect . StretchModeEnum . KeepCentered
139+ } ;
135140
136- //City pop size
137- string popSizeString = "" + city . size ;
138- int popSizeWidth = ( int ) midSizedFont . GetStringSize ( popSizeString ) . X ;
139- int popSizeOffset = LEFT_RIGHT_BOXES_WIDTH / 2 - popSizeWidth / 2 ;
141+ capitalPanel . AddChild ( starTextureRect ) ;
142+ }
140143
141- popSizeLabel . Theme = popSizeTheme ;
144+ private void ApplyStyles ( ) {
145+ // style for the main panel
146+ StyleBoxFlat labelStyle = new ( ) {
147+ BgColor = backgroundGrey ,
148+ BorderColor = borderGrey ,
149+ BorderWidthBottom = 1 ,
150+ BorderWidthLeft = 1 ,
151+ BorderWidthRight = 1 ,
152+ BorderWidthTop = 1
153+ } ;
154+
155+ StyleBoxFlat popStyle = new ( ) {
156+ BgColor = civColor
157+ } ;
158+
159+ StyleBoxLine centerSeparatorStyle = new ( ) {
160+ Color = civColor ,
161+ GrowBegin = CENTRAL_PANEL_SEPARATOR_WIDTH ,
162+ GrowEnd = CENTRAL_PANEL_SEPARATOR_WIDTH ,
163+ } ;
164+
165+ StyleBoxLine bottomBorderStyle = new ( ) {
166+ Color = bottomRowGrey ,
167+ GrowBegin = CENTRAL_PANEL_SEPARATOR_WIDTH ,
168+ GrowEnd = CENTRAL_PANEL_SEPARATOR_WIDTH ,
169+ } ;
170+
171+ StyleBoxLine topBorderStyle = new ( ) {
172+ Color = topRowGrey ,
173+ GrowBegin = CENTRAL_PANEL_SEPARATOR_WIDTH ,
174+ GrowEnd = CENTRAL_PANEL_SEPARATOR_WIDTH ,
175+ } ;
176+
177+ StyleBoxLine separatorStyle = new ( ) {
178+ Color = new Color ( 0 , 0 , 0 , 0 ) , // transparent,
179+ Thickness = CENTRAL_PANEL_SEPARATOR_WIDTH ,
180+ Vertical = true
181+ } ;
182+
183+ labelPanel . AddThemeStyleboxOverride ( "panel" , labelStyle ) ;
184+ popSizePanel . AddThemeStyleboxOverride ( "panel" , popStyle ) ;
185+ centerDivider . AddThemeStyleboxOverride ( "separator" , centerSeparatorStyle ) ;
186+ borderTop . AddThemeStyleboxOverride ( "separator" , topBorderStyle ) ;
187+ borderBottom . AddThemeStyleboxOverride ( "separator" , bottomBorderStyle ) ;
188+ leftSeparator . AddThemeStyleboxOverride ( "separator" , separatorStyle ) ;
189+ rightSeparator . AddThemeStyleboxOverride ( "separator" , separatorStyle ) ;
190+ }
142191
192+ public override void _Draw ( ) {
193+ UpdateContent ( ) ;
194+ }
195+
196+ private void UpdateContent ( ) {
197+ int turnsUntilGrowth = city . TurnsUntilGrowth ( ) ;
198+ string turnsUntilGrowthText = turnsUntilGrowth == int . MaxValue || turnsUntilGrowth < 0 ? "- -" : "" + turnsUntilGrowth ;
199+
200+ cityNameLabel . Text = $ "{ city . name } : { turnsUntilGrowthText } ";
201+ productionLabel . Text = $ "{ city . itemBeingProduced . name } : { city . TurnsUntilProductionFinished ( ) } ";
202+ popSizeLabel . Text = city . size . ToString ( ) ;
203+
204+ // Update population label color based on growth
143205 if ( city . TurnsUntilGrowth ( ) < 0 ) {
144206 popSizeLabel . Theme = popThemeRed ;
207+ } else {
208+ popSizeLabel . Theme = popSizeTheme ;
145209 }
146210
147- popSizeLabel . Text = popSizeString ;
148- popSizeLabel . OffsetLeft = tileCenter . X + cityLabelWidth / - 2 + popSizeOffset ;
149- popSizeLabel . OffsetTop = tileCenter . Y + 22 ;
150- }
211+ // Update the panel with the capital star
212+ bool hasCapitalIndicator = capitalPanel . GetParent ( ) == mainContainer ;
151213
152- private Image CreateLabelBackground ( int cityLabelWidth , City city , int textAreaWidth ) {
153- //Label/name/producing area
154- Image labelImage = Image . Create ( cityLabelWidth , CITY_LABEL_HEIGHT , false , Image . Format . Rgba8 ) ;
155- labelImage . Fill ( Color . Color8 ( 0 , 0 , 0 , 0 ) ) ;
156- byte transparencyLevel = 192 ; //25%
157- Color civColor = Util . LoadColor ( city . owner . colorIndex ) ;
158- civColor = new Color ( civColor , transparencyLevel ) ;
159- Color civColorDarker = Color . Color8 ( 0 , 0 , 138 , transparencyLevel ) ; //todo: automate the darker() function. maybe less transparency?
160- Color topRowGrey = Color . Color8 ( 32 , 32 , 32 , transparencyLevel ) ;
161- Color bottomRowGrey = Color . Color8 ( 48 , 48 , 48 , transparencyLevel ) ;
162- Color backgroundGrey = Color . Color8 ( 64 , 64 , 64 , transparencyLevel ) ;
163- Color borderGrey = Color . Color8 ( 80 , 80 , 80 , transparencyLevel ) ;
164-
165- Image horizontalBorder = Image . Create ( cityLabelWidth - 2 , 1 , false , Image . Format . Rgba8 ) ;
166- horizontalBorder . Fill ( borderGrey ) ;
167- labelImage . BlitRect ( horizontalBorder , new Rect2I ( 0 , 0 , new Vector2I ( cityLabelWidth - 2 , 1 ) ) , new Vector2I ( 1 , 0 ) ) ;
168- labelImage . BlitRect ( horizontalBorder , new Rect2I ( 0 , 0 , new Vector2I ( cityLabelWidth - 2 , 1 ) ) , new Vector2I ( 1 , 22 ) ) ;
169-
170- Image verticalBorder = Image . Create ( 1 , CITY_LABEL_HEIGHT - 2 , false , Image . Format . Rgba8 ) ;
171- verticalBorder . Fill ( borderGrey ) ;
172- labelImage . BlitRect ( verticalBorder , new Rect2I ( 0 , 0 , new Vector2I ( 1 , 23 ) ) , new Vector2I ( 0 , 1 ) ) ;
173- labelImage . BlitRect ( verticalBorder , new Rect2I ( 0 , 0 , new Vector2I ( 1 , 23 ) ) , new Vector2I ( cityLabelWidth - 1 , 1 ) ) ;
174-
175- Image bottomRow = Image . Create ( textAreaWidth , 1 , false , Image . Format . Rgba8 ) ;
176- bottomRow . Fill ( bottomRowGrey ) ;
177- labelImage . BlitRect ( bottomRow , new Rect2I ( 0 , 0 , new Vector2I ( textAreaWidth , 1 ) ) , new Vector2I ( 25 , 21 ) ) ;
178-
179- Image topRow = Image . Create ( textAreaWidth , 1 , false , Image . Format . Rgba8 ) ;
180- topRow . Fill ( topRowGrey ) ;
181- labelImage . BlitRect ( topRow , new Rect2I ( 0 , 0 , new Vector2I ( textAreaWidth , 1 ) ) , new Vector2I ( 25 , 1 ) ) ;
182-
183- Image background = Image . Create ( textAreaWidth , TEXT_ROW_HEIGHT , false , Image . Format . Rgba8 ) ;
184- background . Fill ( backgroundGrey ) ;
185- labelImage . BlitRect ( background , new Rect2I ( 0 , 0 , new Vector2I ( textAreaWidth , 9 ) ) , new Vector2I ( 25 , 2 ) ) ;
186- labelImage . BlitRect ( background , new Rect2I ( 0 , 0 , new Vector2I ( textAreaWidth , 9 ) ) , new Vector2I ( 25 , 12 ) ) ;
187-
188- Image centerDivider = Image . Create ( textAreaWidth , 1 , false , Image . Format . Rgba8 ) ;
189- centerDivider . Fill ( civColor ) ;
190- labelImage . BlitRect ( centerDivider , new Rect2I ( 0 , 0 , new Vector2I ( textAreaWidth , 1 ) ) , new Vector2I ( 25 , 11 ) ) ;
191-
192- Image leftAndRightBoxes = Image . Create ( LEFT_RIGHT_BOXES_WIDTH , LEFT_RIGHT_BOXES_HEIGHT , false , Image . Format . Rgba8 ) ;
193- leftAndRightBoxes . Fill ( civColor ) ;
194- labelImage . BlitRect ( leftAndRightBoxes , new Rect2I ( 0 , 0 , new Vector2I ( 24 , 21 ) ) , new Vector2I ( 1 , 1 ) ) ;
195- if ( city . IsCapital ( ) ) {
196- labelImage . BlitRect ( leftAndRightBoxes , new Rect2I ( 0 , 0 , new Vector2I ( 24 , 21 ) ) , new Vector2I ( cityLabelWidth - 25 , 1 ) ) ;
197- labelImage . BlendRect ( nonEmbassyStar , new Rect2I ( 0 , 0 , new Vector2I ( 18 , 18 ) ) , new Vector2I ( cityLabelWidth - 24 , 2 ) ) ;
214+ if ( city . IsCapital ( ) && ! hasCapitalIndicator ) {
215+ SetupCapitalPanel ( ) ;
216+ mainContainer . AddChild ( capitalPanel ) ;
217+ } else if ( ! city . IsCapital ( ) && hasCapitalIndicator ) {
218+ mainContainer . RemoveChild ( capitalPanel ) ;
198219 }
199- //todo: darker shades of civ color around edges
200- return labelImage ;
220+
221+ labelPanel . Position = new Vector2 ( tileCenter . X - labelPanel . Size . X / 2 , tileCenter . Y + 24 ) ;
222+
223+ // Force the layout to recalculate
224+ labelPanel . Size = Vector2 . Zero ;
201225 }
202226 }
203227}
0 commit comments