/*************************************************
* CustomWindow v1.1.1.2 by Maker
*
* Allows the creation of custom windows.
*
* Requires Table by Bribe and TimerUtils by Vexorian
*
* Importing instructions:
* 1. Import all images with the name beginning with Border.
* There are 8 of them. Also copy background.TGA.
* 2. Make sure the image paths are correct in the globals block in this library.
* 3. Copy CustomTextWindow, Table and TimerUtilsEx into your map.
*
*
* API
*
* struct CustowWindow
*
* o method destroy takes nothing returns nothing
* Destroys a custom window
* o method setHeight takes real height returns nothing
* Sets the height of a custom window
* o method setTransparency takes integer alpha returns nothing
* Sets the transparency of a window
* o method show takes boolean show returns nothing
* Shows/hides a custom window
* o static method create takes real scale, real sizeX, real sizeY, real posX, real posY, integer imageType returns thistype
* Creates a custom window
*
* struct CustomTextWindow
*
* o method destroy takes nothing returns nothing
* Destroys a custom text window
* o method show takes boolean show returns nothing
* Shows/hides a custom text window
* o method setTransparency takes integer alpha returns nothing
* Sets the transparency of a custom text window
* o method fadeOut real time, real delay, boolean destroy returns nothing
* Fades out a custom text window. Time is the fade time, delay the time before fading.
* If destroy is true, the window will be destroyed when it has faded out.
* o method setHeight real height returns nothing
* Sets the height of a custom window
* o static method create takes string title, string text, real posX, real posY, real textSize, real borderScale, integer maxWidth, integer imageType returns thistype
* Creates a custom text window
*
*
* Try to avoid large text sizes, over about 28, since
* the game engine will add a line break if text tag width
* would become too large.
*
************************************************/
library CustomWindow requires Table, TimerUtils
globals
private constant string BACKGROUND = "war3mapImported\\background.TGA"
private constant string BOTTOM_L = "war3mapImported\\BorderDownLeftNE.TGA"
private constant string TOP_L = "war3mapImported\\BorderUpLeftNE.TGA"
private constant string BOTTOM_R = "war3mapImported\\BorderDownRightNE.TGA"
private constant string TOP_R = "war3mapImported\\BorderUpRightNE.TGA"
private constant string LEFT = "war3mapImported\\BorderLeftNE.TGA"
private constant string TOP = "war3mapImported\\BorderUpNE.TGA"
private constant string RIGHT = "war3mapImported\\BorderRightNE.TGA"
private constant string BOTTOM = "war3mapImported\\BorderDownNE.TGA"
private constant integer TRANS = 200 // Transparency of the background, 0 = fully transparent, 255 = not transparent
private constant integer MAXCHARS = 38 // Maximum number of characters in a row
private constant real CHARHEIGHT = 4 // Height of a letter in pixels
private constant real CHARWIDTH = 1.5 // Width of a letter in pixels
private constant real BORDERWIDTH = 28 // Width of borders, visible portion of default size
private constant real LOOPTIME = 0.03125
/* Use CHARHEIGHT and CHARWIDTH to adjust the window's wrapping around the text */
endglobals
// Not to be changed
globals
private real X
private real Y
private constant real DEFSIZE = 64 // Size of visible portion of an image
private constant real RATIO = (DEFSIZE+2)/DEFSIZE
private location LOC = Location(0,0)
endglobals
struct CustomWindow extends array
private integer images
private static Table array imgs
private static integer ic = 0
private static integer ir = 0
private thistype rn
method destroy takes nothing returns nothing
local integer i = this.images
loop
exitwhen i == 0
call DestroyImage(imgs[this].image[i])
set i = i - 1
endloop
call imgs[this].destroy()
set .rn = ir
set ir = this
endmethod
method setHeight takes real height returns nothing
local integer i = .images
loop
exitwhen i == 0
call SetImageConstantHeight(imgs[this].image[i], true, height)
set i = i - 1
endloop
endmethod
method show takes boolean show returns nothing
local integer i = .images
loop
exitwhen i == 0
call SetImageRenderAlways(imgs[this].image[i], show)
call ShowImage(imgs[this].image[i], show)
set i = i - 1
endloop
endmethod
method setTransparency takes integer alpha returns nothing
local integer i = .images
loop
exitwhen i == 0
if i != 1 then
call SetImageColor(imgs[this].image[i], 255, 255, 255, alpha)
elseif alpha < TRANS then
call SetImageColor(imgs[this].image[i], 255, 255, 255, alpha)
else
call SetImageColor(imgs[this].image[i], 255, 255, 255, TRANS)
endif
set i = i - 1
endloop
endmethod
private static method addRecycle takes nothing returns thistype
local thistype this
if ir == 0 then
set ic = ic + 1
set this = ic
else
set this = ir
set ir = .rn
endif
return this
endmethod
// posX and posY are the coordinates of the center of the image
static method create takes real borderScale, real sizeX, real sizeY, real posX, real posY, integer imageType returns thistype
local thistype this = thistype.addRecycle()
local integer i = 0 // Image counter
local integer j // For loops
local integer nx = 0 // How many x pieces
local integer ny = 0 // How many y pieces
local real sx = 0 // X size
local real sy = 0 // Y size
local real cx = 0 // X coordinate of lower left corner
local real cy = 0 // Y coordinate of lower left corner
local real bwidth // Border width
local real sxa
local real sya
set X = DEFSIZE*borderScale // Visible image size of one image
set Y = DEFSIZE*borderScale
set bwidth = BORDERWIDTH * borderScale // Visible border width
set imgs[this] = Table.create()
if sizeX < 2*X then
set sizeX = 2*X
endif
set sx = X * RATIO // X size of one block, corners
set nx = R2I((sizeX-2*X) / X) // How many top/bottom blocks, excluding corner blocks
set sxa = (sizeX-2*X) / (nx * X) * sx // X size of one block, top and bottom
set cx = posX - sizeX/2 + X - borderScale
if sizeY < 2*Y then
set sizeY = 2*Y
endif
set sy = Y * RATIO
set ny = R2I((sizeY-2*Y) / Y)
set sya = (sizeY-2*X) / (ny * X) * sy
set cy = posY - sizeY/2 + Y - borderScale
set i = i + 1 // Background
set imgs[this].image[i] = CreateImage(BACKGROUND, sizeX-bwidth, sizeY-bwidth, 0, posX - (sizeX-bwidth)/2, posY - (sizeY-bwidth)/2, 0, 0, 0, 0, imageType)
call SetImageColor(imgs[this].image[i], 255, 255, 255, TRANS)
set posX = posX - borderScale
set posY = posY - borderScale
set i = i + 1 // Down left corner
set imgs[this].image[i] = CreateImage(BOTTOM_L, sx, sy, 0, posX - sizeX/2, posY - sizeY/2, 0, 0, 0, 0, imageType)
set i = i + 1 // Up left corner
set imgs[this].image[i] = CreateImage(TOP_L, sx, sy, 0, posX - sizeX/2, posY + sizeY/2 - sy/RATIO, 0, 0, 0, 0, imageType)
set i = i + 1 // Up right corner
set imgs[this].image[i] = CreateImage(TOP_R, sx, sy, 0, posX + sizeX/2 - X, posY + sizeY/2 - sy/RATIO, 0, 0, 0, 0, imageType)
set i = i + 1 // Down right corner
set imgs[this].image[i] = CreateImage(BOTTOM_R, sx, sy, 0, posX + sizeX/2 - X, posY - sizeY/2, 0, 0, 0, 0, imageType)
set j = 0
loop // Up and down blocks
set i = i + 1
set imgs[this].image[i] = CreateImage(TOP, sxa, sy, 0, cx, posY + sizeY/2 - Y, 0, 0, 0, 0, imageType)
set i = i + 1
set imgs[this].image[i] = CreateImage(BOTTOM, sxa, sy, 0, cx, posY - sizeY/2, 0, 0, 0, 0, imageType)
set j = j + 1
exitwhen j == nx
set cx = cx + sxa/RATIO
endloop
set j = 0
loop // Left and right blocks
set i = i + 1
set imgs[this].image[i] = CreateImage(LEFT, sx, sya, 0, posX - sizeX/2, cy, 0, 0, 0, 0, imageType)
set i = i + 1
set imgs[this].image[i] = CreateImage(RIGHT, sx, sya, 0, posX + sizeX/2 - X, cy, 0, 0, 0, 0, imageType)
set j = j + 1
exitwhen j == ny
set cy = cy + sya/RATIO
endloop
set this.images = i
return this
endmethod
endstruct
struct CustomTextWindow extends array
private real ttPosX
private real ttPosY
private real height
private real ttSize
private integer visibility
private integer fadeRate
private integer fadeOutRate
private timer t
private timer tOut
private string title
private string text
texttag tt
private boolean destroys
private boolean destroysOut
CustomWindow cw
private thistype rn
private static integer ic = 0
private static integer ir = 0
method destroy takes nothing returns nothing
if this.tt != null then
call DestroyTextTag(this.tt)
set this.tt = null
endif
set this.title = null
set this.text = null
set this.destroys = false
if this.t != null then
call ReleaseTimer(this.t)
set this.t = null
endif
if this.tOut != null then
call ReleaseTimer(this.tOut)
set this.tOut = null
endif
call this.cw.destroy()
set this.rn = ir
set ir = this
endmethod
method setTransparency takes integer alpha returns nothing
set this.visibility = alpha
if this.tt == null and alpha > 0 and alpha < 255 then
call this.show(true)
call SetTextTagPermanent(this.tt, false)
call SetTextTagColor(this.tt, 255, 255, 255, alpha)
elseif alpha > 0 then
call SetTextTagColor(this.tt, 255, 255, 255, alpha)
elseif this.tt != null and alpha <= 0 then
call DestroyTextTag(this.tt)
set this.tt = null
endif
call this.cw.setTransparency(alpha)
endmethod
method show takes boolean show returns nothing
if show then
if this.tt == null then
call MoveLocation(LOC, .ttPosX, .ttPosY)
set this.tt = CreateTextTag()
call SetTextTagText(this.tt, this.text, this.ttSize/1000)
call SetTextTagPos(this.tt, this.ttPosX, this.ttPosY, .height - GetLocationZ(LOC))
call SetTextTagColor(this.tt, 255, 255, 255, 255)
call SetTextTagVisibility(this.tt, true)
endif
else
if this.t != null then
call PauseTimer(this.t)
endif
call DestroyTextTag(this.tt)
set this.tt = null
endif
call this.cw.show(show)
endmethod
private static method fade takes nothing returns nothing
local thistype this = GetTimerData(GetExpiredTimer())
set this.visibility = this.visibility - this.fadeRate
if this.visibility > 0 and this.visibility < 255 then
call this.setTransparency(this.visibility)
else
call PauseTimer(this.t)
if this.destroys then
call this.destroy()
else
if this.fadeRate < 0 then
call this.setTransparency(255)
elseif this.fadeRate > 0 then
call this.setTransparency(0)
endif
if this.t != null then
call ReleaseTimer(this.t)
set this.t = null
endif
endif
endif
endmethod
private static method fadeDelay takes nothing returns nothing
local thistype this = GetTimerData(GetExpiredTimer())
set this.fadeRate = this.fadeOutRate
set this.destroys = this.destroysOut
call SetTextTagPermanent(this.tt, false)
if this.tOut != null then
call ReleaseTimer(this.tOut)
set this.tOut = null
endif
if this.t == null then
set this.t = NewTimerEx(this)
endif
call TimerStart(this.t, LOOPTIME, true, function thistype.fade)
endmethod
method fadeIn takes real time returns nothing
if .t == null then
set .t = NewTimerEx(this)
endif
if time == 0 then
set time = 0.01
endif
set .destroys = false
set .fadeRate = -(R2I(255*LOOPTIME/time) + 1)
call SetTextTagPermanent(.tt, false)
call TimerStart(.t, LOOPTIME, true, function thistype.fade)
endmethod
method fadeOut takes real time, real delay, boolean destroys returns nothing
if time == 0 then
set time = 0.01
endif
set .fadeOutRate = R2I(255*LOOPTIME/time) + 1
set .destroysOut = destroys
call SetTextTagPermanent(.tt, false)
if delay != 0 then
if .tOut == null then
set .tOut = NewTimerEx(this)
endif
call TimerStart(.tOut, delay, false, function thistype.fadeDelay)
else
if .tOut != null then
call PauseTimer(.tOut)
endif
if .t == null then
set .t = NewTimerEx(this)
endif
set this.fadeRate = this.fadeOutRate
set this.destroys = this.destroysOut
call TimerStart(.t, LOOPTIME, true, function thistype.fade)
endif
endmethod
method setHeight takes real height returns nothing
call MoveLocation(LOC, .ttPosX, .ttPosY)
call SetTextTagPos(.tt, .ttPosX, .ttPosY, height - GetLocationZ(LOC))
call this.cw.setHeight(height)
set .height = height
endmethod
private static method addRecycle takes nothing returns thistype
local thistype this
if 0==ir then
set ic=ic+1
set this=ic
else
set this=ir
set ir=.rn
endif
return this
endmethod
// posX and pos Y are the coordinates of bottom left corner
static method create takes string title, string text, real posX, real posY, real textSize, real borderScale, integer maxWidth, integer imageType returns thistype
local thistype this = thistype.addRecycle()
local integer i
local integer rows = 1
local integer wordlength = 0
local string word = null
local string newStr = null
local string char
local integer chars = 0
local integer charsMax = 0
local real width
local real sizeX
local real sizeY
if maxWidth > MAXCHARS or maxWidth == 0 then
set maxWidth = MAXCHARS
endif
if text != null then
set rows = rows + 1
set width = 0
set i = 0
loop
set char = SubString(text, i, i+1)
if char == " " or char == "" then
if chars < maxWidth then
set newStr = newStr + " " + word
if char == " " then
set chars = chars + 1
endif
if chars > charsMax then
set charsMax = chars
endif
else
if chars - wordlength > charsMax then
set charsMax = chars - wordlength
endif
set newStr = newStr + "\n" + " " + word
set chars = 1 + wordlength
set rows = rows + 1
endif
set word = null
set wordlength = 0
else
set chars = chars + 1
set wordlength = wordlength + 1
set word = word + char
endif
exitwhen char == ""
set i = i + 1
endloop
else
set charsMax = StringLength(title) + 2
endif
call MoveLocation(LOC, posX, posY)
set this.height = GetLocationZ(LOC)
set sizeX = charsMax * CHARWIDTH * textSize/5 + 2*DEFSIZE*borderScale
set sizeY = rows * CHARHEIGHT * textSize/5 + 2*DEFSIZE*borderScale
set this.ttSize = textSize
set this.ttPosX = posX
set this.ttPosY = posY
set this.title = title
set this.text = "|cffffcc00" + this.title + "|r\n" + newStr
set this.cw = CustomWindow.create(borderScale, sizeX, sizeY, posX+sizeX/2-DEFSIZE*borderScale, posY+sizeY/2-DEFSIZE*borderScale, imageType)
set char = null
set newStr = null
return this
endmethod
endstruct
endlibrary