UI Tutorial discussion thread

Welcome to the wonderful world of Lua sand-boxing!

Both Controls and ContextPtr are local to the InGameUIAddin context, so you can't do Controls.Message (which is in WonderRaceDialog.lua/xml) from WonderRaceStart.lua

There are several ways out of your problem, but the one that'll probably leave you cussing Civ5/Lua the least is ...

Starting from the .civ5mod file you posted above

  • I've moved both WonderRaceDialog.xml and WonderRaceDialog.lua files into a "ui" sub-folder (it's just personal preference).
  • Both of those files are VFS=false
  • I've added the InGameUIAddin for WonderRaceDialog.xml
  • I've removed the InGameUIAddin for WonderRaceStart.lua
  • and set it to VFS=true
  • I've removed "include("WonderRaceDialog.lua")" from WonderRaceStart.lua
  • I've added "include("WonderRaceStart.lua")" to WonderRaceDialog.lua
Lua include basically does a copy-and-paste, so we need all the "smarts" inside the UI stuff, so that the smart stuff can get hold of ContextPtr and Controls and control the popup.

If that doesn't work (or appeal) ditch the WonderRaceStart.lua file and just copy it into the WonderRaceDialog.lua file

Or if you don't like that, send LuaEvent messages between them (really not recommended)
 
How do I actually call it with a function using show()?

If I use
Code:
function SeductressMission()
	ContextPtr:SetHide(false)
end
How does it know that is the popup I want to appear? Can I only have one?
I want to use it for a Mission, where I must choose a Civ in a drop-down menu and do stuff with it (already wrote the code for that, though, just need the popup to work :().

Also, how to deactivate the automatic showing on starting a game?

I swear I read all the PDFs, even the eigth, but I'm very new at Lua and this is pretty important for the mod I pretend to launch in a few weeks.
 
Like most things, the answer is "it depends"

If your UI overlay adds it's own button to the main interface to bring up your dialog, you need the button "always on" and use it to show/hide the dialog.

If your overlay is adding a popup, you can use the BUTTONPOPUP mechanism to show/hide it

Alternatively, you can use a LuaEvent to show/hide the dialog. I happen to prefer this way as you can then easily open/close the dialog from many UI events (button, menu item, control-key, etc) and also from code.

To hide your UI context initially, add a ContextPtr:SetHide(true) as the very last line of the context's Lua file (ie outside of all other functions)
 
SetColor() works for a label, eg from Menu2 (see below), but be aware that Lua expects RGBA to be 0.0 to 1.0 (not 0 to 255) and you need to specify which "colour channel" you want to set (the main foreground channel is 0 - the other two are drop shadow and something else I've forgotten!)

Code:
<Label ID="CSName" Anchor="L,C" Offset="40,0" Font="TwCenMT20" FontStyle="Shadow" ColorSet="Beige_Black_Alpha">
  <Image ID="CSIcon" Anchor="L,C" AnchorSide="O,I" Size="32,32" Texture="CivSymbolAtlas32.dds" Color="201,248,255,255"/>
</Label>

Code:
function SetCsDetails(pCS, entry)
  entry.CSName:SetText(pCS:GetName())
  entry.CSIcon:SetTexture(GameInfo.MinorCivTraits[GameInfo.MinorCivilizations[pCS:GetMinorCivType()].MinorCivTrait].TraitIcon)
  entry.CSIcon:SetHide(false)

  local _, csColour = pCS:GetPlayerColors(); csColour.w = 1
  entry.CSIcon:SetColor(csColour)
  [B][COLOR="Red"]entry.CSName:SetColor(csColour, 0)[/COLOR][/B]
end

You can also set by colour name, eg from Menu3

Code:
  Controls.CSName:SetColorByName("Beige_Black_Alpha")

Or you can embed [COLOR_...]...[ENDCOLOR] tags into the text
 
the main foreground channel is 0 - the other two are drop shadow and something else I've forgotten!)

That's what I was missing! Thank you for a very detailed reply as well - I'll be sure to put these other capabilities to use!

Quick related Q, what's the distinction between "Beige_Black" (this is the default in BNW, I think?) and "Beige_Black_Alpha"? Just some transparency?
 
See ColorAtlas.xml

Code:
  <ColorSet Name="Beige_Black" Color0="Beige" Color1="Black" />
  <ColorSet Name="Beige_Black_Alpha" Color0="Beige" Color1="Black,200" />
 
Tutorial 2b Stacked Stacks does not come with any walkthrough in the archive. And the link to the civfanatics resource is just a double to the Tutorial 2 Buttons resource. Did you abandon this component of the 'curriculum'?
 
There's a whole thread about scroll panels within scroll panels somewhere (which is what 2b came from) - but I can't find it.

The walk-through is basically via comments in the code, but as the first main comments in the xml/lua files are

"Scroll panels within scroll panels fundamentally don't work. Normal controls (text, images, boxes, etc) within a scroll panel are cropped to fit, but if ANY part of a scroll panel is visible the entire panel is shown which causes the inner panel to "bleed" outside the limits of the containing panel."

and

"Also illustrates why scroll panels within scroll panels are a complete nightmare!"

It's a strong hint you're wasting your time trying to get them to work!
 
edit: I've managed to circumvent the issue by using a stack of containers instead. While an answer would still be of some interest for future reference, it's not particularly urgent now.

I've been trying to get an UI addition running recently and your tutorial is helping immensely, but I've got a nagging problem I'm not sure how to fix. I'm trying to generate a list showing cultural influences on known civs. The first time I bring the screen up, it looks like this, which is good for now (this is turn 1, so no-one has been influenced by another's tourism; plus I'll restrict the list to known civs later on).
attachment.php

For each civ, the Label and Bar are instantiated inside a horizontal Stack which is itself instantiated inside a vertical Stack. Now when I hide the screen and bring it up again, what is supposed to happen is that the instance manager clears out the main stack (using g_CivStackManager:ResetInstances() as in the tutorial) and repopulates it.
However, what I see instead is this.
2vkj2ut.jpg

My best guess is that the instantiated stacks are not properly wiped and then get added to. But I wouldn't know what I did wrong.
My xml is as follows:
Code:
<?xml version="1.0" encoding="utf-8" ?>
<Context>
	<Instance Name="MajorCiv">
		<Stack ID="SubStack" Anchor="L,C" StackGrowth="Right"/>
	</Instance>
	<Instance Name="BasicLabel">
		<Label ID="Label" Anchor="L,C" Font="TwCenMT24" FontStyle="Shadow" ColorSet="Beige_Black_Alpha"/>		
	</Instance>
	<Instance Name="IndigenousBar">
		<Bar ID="Bar" Anchor="R,T" Offset="50,0" Size="150,8"	Direction="Right" FGColor="Culture,255" BGColor="Culture,128" ToolTip=""/>
	</Instance>
	
	<Grid Size="400,400" Anchor="C,C" Style="Grid9DetailFive140" ConsumeMouse="1">
		<Label Anchor="C,T" Font="TwCenMT24" FontStyle="Shadow" ColorSet="Beige_Black_Alpha" String="TXT_KEY_TEST_DIALOG_MESSAGE"/>
		<Stack ID="MainStack" Offset="50,0" Anchor="L,C" StackGrowth="Bottom" Padding="5"/>
		<GridButton ID="OK" Size="140, 36" Anchor="C,B" Offset="0,50" Style="BaseButton" ToolTip="TXT_KEY_TEST_DIALOG_BUTTON_OK_TT">
			<Label  Anchor="C,C" Offset="0,-2" String="TXT_KEY_TEST_DIALOG_BUTTON_OK" Font="TwCenMT24" FontStyle="Shadow" ColorSet="Beige_Black_Alpha" />
		</GridButton>
	</Grid>
</Context>
The relevant parts of my lua are as follows:
Code:
include("InstanceManager")
print("--- Initializing Cultural Composition overview screen ---")
local g_CivStackManager = InstanceManager:new("MajorCiv","SubStack",Controls.MainStack)

function Init()
	Hide()
end

function DoCivBars()
	g_CivStackManager:ResetInstances()
	for iC = 0, GameDefines.MAX_MAJOR_CIVS-1, 1 do
		local pPlayer = Players[iC]
		if (pPlayer:IsEverAlive() and pPlayer:IsAlive()) then
			AddCivBar(iC)
		end
	end
	Controls.MainStack:CalculateSize()
	Controls.MainStack:ReprocessAnchoring()
end

function AddCivBar(iPlayer)
	local pPlayer = Players[iPlayer]
	local instance = g_CivStackManager:GetInstance()
			
	local g_LabelManager = InstanceManager:new("BasicLabel","Label",instance.SubStack)
	local Name = g_LabelManager:GetInstance()
	Name.Label:SetText(pPlayer:GetCivilizationShortDescription())

	local g_BarManager = InstanceManager:new("IndigenousBar","Bar",instance.SubStack)
	local IndigenousBar = g_BarManager:GetInstance()

	local fPercent = 1.0
	if CombinedInfluenceOn(iC) > 0 then fPercent = pPlayer:GetJONSCultureEverGenerated() / CombinedInfluenceOn(iC) end
	IndigenousBar.Bar:SetPercent(fPercent)

	IndigenousBar.Bar:SetToolTipString(Tooltip(iPlayer))
	IndigenousBar.Bar:EnableToolTip(true)
end

--------------------------------------------------------------

function Show()
	DoCivBars()
	ContextPtr:SetHide(false)
end
 

Attachments

  • influenceboxA.jpg
    influenceboxA.jpg
    120.7 KB · Views: 218
  • influenceboxB.jpg
    influenceboxB.jpg
    124.4 KB · Views: 71
The problem is being cause because while you are calling ResetInstances() on the main (vertical) g_CivStackManager stack, you're not calling it for each of the horizontal IndigenousBar stacks.

When you get a g_CivStackManager instance, you'll need to check if it already has an IndigenousBar instance, if so clear it and reuse it, if not create a new one and store it

Code:
local instance = g_CivStackManager:GetInstance()
local IndigenousBar

if (instance.IndigenousBar) then
  IndigenousBar = instance.IndigenousBar
  IndigenousBar:ResetInstances()
else
  IndigenousBar = g_BarManager:GetInstance()
  instance.IndigenousBar = IndigenousBar 
endif

Edit: And you'll need to do the same for the Name as well
 
Back
Top Bottom