mirror of
https://github.com/Maruno17/pokemon-essentials.git
synced 2025-09-24 18:41:27 +02:00
1373 lines
38 KiB
Ruby
1373 lines
38 KiB
Ruby
#===============================================================================
|
|
# Represents a window with no formatting capabilities. Its text color can be set,
|
|
# though, and line breaks are supported, but the text is generally unformatted.
|
|
#===============================================================================
|
|
class Window_UnformattedTextPokemon < SpriteWindow_Base
|
|
attr_reader :text
|
|
attr_reader :baseColor
|
|
attr_reader :shadowColor
|
|
# Letter-by-letter mode. This mode is not supported in this class.
|
|
attr_accessor :letterbyletter
|
|
|
|
def text=(value)
|
|
@text = value
|
|
refresh
|
|
end
|
|
|
|
def baseColor=(value)
|
|
@baseColor = value
|
|
refresh
|
|
end
|
|
|
|
def shadowColor=(value)
|
|
@shadowColor = value
|
|
refresh
|
|
end
|
|
|
|
def initialize(text = "")
|
|
super(0, 0, 33, 33)
|
|
self.contents = Bitmap.new(1, 1)
|
|
pbSetSystemFont(self.contents)
|
|
@text = text
|
|
@letterbyletter = false # Not supported in this class
|
|
colors = getDefaultTextColors(self.windowskin)
|
|
@baseColor = colors[0]
|
|
@shadowColor = colors[1]
|
|
resizeToFit(text)
|
|
end
|
|
|
|
def self.newWithSize(text, x, y, width, height, viewport = nil)
|
|
ret = self.new(text)
|
|
ret.x = x
|
|
ret.y = y
|
|
ret.width = width
|
|
ret.height = height
|
|
ret.viewport = viewport
|
|
ret.refresh
|
|
return ret
|
|
end
|
|
|
|
# maxwidth is maximum acceptable window width.
|
|
def resizeToFitInternal(text, maxwidth)
|
|
dims = [0, 0]
|
|
cwidth = maxwidth < 0 ? Graphics.width : maxwidth
|
|
getLineBrokenChunks(self.contents, text,
|
|
cwidth - self.borderX - SpriteWindow_Base::TEXT_PADDING, dims, true)
|
|
return dims
|
|
end
|
|
|
|
def setTextToFit(text, maxwidth = -1)
|
|
resizeToFit(text, maxwidth)
|
|
self.text = text
|
|
end
|
|
|
|
# maxwidth is maximum acceptable window width.
|
|
def resizeToFit(text, maxwidth = -1)
|
|
dims = resizeToFitInternal(text, maxwidth)
|
|
self.width = dims[0] + self.borderX + SpriteWindow_Base::TEXT_PADDING
|
|
self.height = dims[1] + self.borderY
|
|
refresh
|
|
end
|
|
|
|
# width is current window width.
|
|
def resizeHeightToFit(text, width = -1)
|
|
dims = resizeToFitInternal(text, width)
|
|
self.width = (width < 0) ? Graphics.width : width
|
|
self.height = dims[1] + self.borderY
|
|
refresh
|
|
end
|
|
|
|
def setSkin(skin)
|
|
super(skin)
|
|
privRefresh(true)
|
|
oldbaser = @baseColor.red
|
|
oldbaseg = @baseColor.green
|
|
oldbaseb = @baseColor.blue
|
|
oldbasea = @baseColor.alpha
|
|
oldshadowr = @shadowColor.red
|
|
oldshadowg = @shadowColor.green
|
|
oldshadowb = @shadowColor.blue
|
|
oldshadowa = @shadowColor.alpha
|
|
colors = getDefaultTextColors(self.windowskin)
|
|
@baseColor = colors[0]
|
|
@shadowColor = colors[1]
|
|
if oldbaser != @baseColor.red || oldbaseg != @baseColor.green ||
|
|
oldbaseb != @baseColor.blue || oldbasea != @baseColor.alpha ||
|
|
oldshadowr != @shadowColor.red || oldshadowg != @shadowColor.green ||
|
|
oldshadowb != @shadowColor.blue || oldshadowa != @shadowColor.alpha
|
|
self.text = self.text
|
|
end
|
|
end
|
|
|
|
def refresh
|
|
self.contents = pbDoEnsureBitmap(self.contents, self.width - self.borderX,
|
|
self.height - self.borderY)
|
|
self.contents.clear
|
|
drawTextEx(self.contents, 0, -2, self.contents.width, 0, # TEXT OFFSET
|
|
@text.gsub(/\r/, ""), @baseColor, @shadowColor)
|
|
end
|
|
end
|
|
|
|
#===============================================================================
|
|
#
|
|
#===============================================================================
|
|
class Window_AdvancedTextPokemon < SpriteWindow_Base
|
|
attr_reader :text
|
|
attr_reader :baseColor
|
|
attr_reader :shadowColor
|
|
attr_accessor :letterbyletter
|
|
attr_reader :waitcount
|
|
|
|
def initialize(text = "")
|
|
@cursorMode = MessageConfig::CURSOR_POSITION
|
|
@endOfText = nil
|
|
@scrollstate = 0
|
|
@scrollY = 0
|
|
@scroll_timer_start = nil
|
|
@realframes = 0
|
|
@nodraw = false
|
|
@lineHeight = 32
|
|
@linesdrawn = 0
|
|
@bufferbitmap = nil
|
|
@letterbyletter = false
|
|
@starting = true
|
|
@displaying = false
|
|
@lastDrawnChar = -1
|
|
@fmtchars = []
|
|
@text_delay_changed = false
|
|
@text_delay = MessageConfig.pbGetTextSpeed
|
|
super(0, 0, 33, 33)
|
|
@pausesprite = nil
|
|
@text = ""
|
|
self.contents = Bitmap.new(1, 1)
|
|
pbSetSystemFont(self.contents)
|
|
self.resizeToFit(text, Graphics.width)
|
|
colors = getDefaultTextColors(self.windowskin)
|
|
@baseColor = colors[0]
|
|
@shadowColor = colors[1]
|
|
self.text = text
|
|
@starting = false
|
|
end
|
|
|
|
def self.newWithSize(text, x, y, width, height, viewport = nil)
|
|
ret = self.new(text)
|
|
ret.x = x
|
|
ret.y = y
|
|
ret.width = width
|
|
ret.height = height
|
|
ret.viewport = viewport
|
|
return ret
|
|
end
|
|
|
|
def dispose
|
|
return if disposed?
|
|
@pausesprite&.dispose
|
|
@pausesprite = nil
|
|
super
|
|
end
|
|
|
|
def waitcount=(value)
|
|
@waitcount = (value <= 0) ? 0 : value
|
|
@wait_timer_start = System.uptime if !@wait_timer_start && value > 0
|
|
end
|
|
|
|
attr_reader :cursorMode
|
|
|
|
def cursorMode=(value)
|
|
@cursorMode = value
|
|
moveCursor
|
|
end
|
|
|
|
def lineHeight=(value)
|
|
@lineHeight = value
|
|
self.text = self.text
|
|
end
|
|
|
|
def baseColor=(value)
|
|
@baseColor = value
|
|
refresh
|
|
end
|
|
|
|
def shadowColor=(value)
|
|
@shadowColor = value
|
|
refresh
|
|
end
|
|
|
|
# Delay in seconds between two adjacent characters appearing.
|
|
def textspeed
|
|
return @text_delay
|
|
end
|
|
|
|
def textspeed=(value)
|
|
@text_delay_changed = true if @text_delay != value
|
|
@text_delay = value
|
|
end
|
|
|
|
def width=(value)
|
|
super
|
|
self.text = self.text if !@starting
|
|
end
|
|
|
|
def height=(value)
|
|
super
|
|
self.text = self.text if !@starting
|
|
end
|
|
|
|
def resizeToFit(text, maxwidth = -1)
|
|
dims = resizeToFitInternal(text, maxwidth)
|
|
oldstarting = @starting
|
|
@starting = true
|
|
self.width = dims[0] + self.borderX + SpriteWindow_Base::TEXT_PADDING
|
|
self.height = dims[1] + self.borderY
|
|
@starting = oldstarting
|
|
redrawText
|
|
end
|
|
|
|
def resizeToFit2(text, maxwidth, maxheight)
|
|
dims = resizeToFitInternal(text, maxwidth)
|
|
oldstarting = @starting
|
|
@starting = true
|
|
self.width = [dims[0] + self.borderX + SpriteWindow_Base::TEXT_PADDING, maxwidth].min
|
|
self.height = [dims[1] + self.borderY, maxheight].min
|
|
@starting = oldstarting
|
|
redrawText
|
|
end
|
|
|
|
def resizeToFitInternal(text, maxwidth)
|
|
dims = [0, 0]
|
|
cwidth = (maxwidth < 0) ? Graphics.width : maxwidth
|
|
chars = getFormattedTextForDims(self.contents, 0, 0,
|
|
cwidth - self.borderX - 2 - 6, -1, text, @lineHeight, true)
|
|
chars.each do |ch|
|
|
dims[0] = [dims[0], ch[1] + ch[3]].max
|
|
dims[1] = [dims[1], ch[2] + ch[4]].max
|
|
end
|
|
return dims
|
|
end
|
|
|
|
def resizeHeightToFit(text, width = -1)
|
|
dims = resizeToFitInternal(text, width)
|
|
oldstarting = @starting
|
|
@starting = true
|
|
self.width = (width < 0) ? Graphics.width : width
|
|
self.height = dims[1] + self.borderY
|
|
@starting = oldstarting
|
|
redrawText
|
|
end
|
|
|
|
def setSkin(skin, redrawText = true)
|
|
super(skin)
|
|
privRefresh(true)
|
|
oldbaser = @baseColor.red
|
|
oldbaseg = @baseColor.green
|
|
oldbaseb = @baseColor.blue
|
|
oldbasea = @baseColor.alpha
|
|
oldshadowr = @shadowColor.red
|
|
oldshadowg = @shadowColor.green
|
|
oldshadowb = @shadowColor.blue
|
|
oldshadowa = @shadowColor.alpha
|
|
colors = getDefaultTextColors(self.windowskin)
|
|
@baseColor = colors[0]
|
|
@shadowColor = colors[1]
|
|
if redrawText &&
|
|
(oldbaser != @baseColor.red || oldbaseg != @baseColor.green ||
|
|
oldbaseb != @baseColor.blue || oldbasea != @baseColor.alpha ||
|
|
oldshadowr != @shadowColor.red || oldshadowg != @shadowColor.green ||
|
|
oldshadowb != @shadowColor.blue || oldshadowa != @shadowColor.alpha)
|
|
setText(self.text)
|
|
end
|
|
end
|
|
|
|
def setTextToFit(text, maxwidth = -1)
|
|
resizeToFit(text, maxwidth)
|
|
self.text = text
|
|
end
|
|
|
|
def text=(value)
|
|
setText(value)
|
|
end
|
|
|
|
def setText(value)
|
|
@waitcount = 0
|
|
@wait_timer_start = nil
|
|
@display_timer = 0.0
|
|
@display_last_updated = System.uptime
|
|
@curchar = 0
|
|
@drawncurchar = -1
|
|
@lastDrawnChar = -1
|
|
@text = value
|
|
@textlength = unformattedTextLength(value)
|
|
@scrollstate = 0
|
|
@scrollY = 0
|
|
@scroll_timer_start = nil
|
|
@linesdrawn = 0
|
|
@realframes = 0
|
|
@textchars = []
|
|
width = 1
|
|
height = 1
|
|
numlines = 0
|
|
visiblelines = (self.height - self.borderY) / @lineHeight
|
|
if value.length == 0
|
|
@fmtchars = []
|
|
@bitmapwidth = width
|
|
@bitmapheight = height
|
|
@numtextchars = 0
|
|
else
|
|
if @letterbyletter
|
|
@fmtchars = []
|
|
fmt = getFormattedText(self.contents, 0, 0,
|
|
self.width - self.borderX - SpriteWindow_Base::TEXT_PADDING, -1,
|
|
shadowc3tag(@baseColor, @shadowColor) + value, @lineHeight, true)
|
|
@oldfont = self.contents.font.clone
|
|
fmt.each do |ch|
|
|
chx = ch[1] + ch[3]
|
|
chy = ch[2] + ch[4]
|
|
width = chx if width < chx
|
|
height = chy if height < chy
|
|
if !ch[5] && ch[0] == "\n"
|
|
numlines += 1
|
|
if numlines >= visiblelines
|
|
fclone = ch.clone
|
|
fclone[0] = "\1"
|
|
@fmtchars.push(fclone)
|
|
@textchars.push("\1")
|
|
end
|
|
end
|
|
# Don't add newline characters, since they
|
|
# can slow down letter-by-letter display
|
|
if ch[5] || (ch[0] != "\r")
|
|
@fmtchars.push(ch)
|
|
@textchars.push(ch[5] ? "" : ch[0])
|
|
end
|
|
end
|
|
fmt.clear
|
|
else
|
|
@fmtchars = getFormattedText(self.contents, 0, 0,
|
|
self.width - self.borderX - SpriteWindow_Base::TEXT_PADDING, -1,
|
|
shadowc3tag(@baseColor, @shadowColor) + value, @lineHeight, true)
|
|
@oldfont = self.contents.font.clone
|
|
@fmtchars.each do |ch|
|
|
chx = ch[1] + ch[3]
|
|
chy = ch[2] + ch[4]
|
|
width = chx if width < chx
|
|
height = chy if height < chy
|
|
@textchars.push(ch[5] ? "" : ch[0])
|
|
end
|
|
end
|
|
@bitmapwidth = width
|
|
@bitmapheight = height
|
|
@numtextchars = @textchars.length
|
|
end
|
|
stopPause
|
|
@displaying = @letterbyletter
|
|
@needclear = true
|
|
@nodraw = @letterbyletter
|
|
refresh
|
|
end
|
|
|
|
def busy?
|
|
return @displaying
|
|
end
|
|
|
|
def pausing?
|
|
return @pausing && @displaying
|
|
end
|
|
|
|
def resume
|
|
if !busy?
|
|
self.stopPause
|
|
return true
|
|
end
|
|
if @pausing
|
|
@pausing = false
|
|
self.stopPause
|
|
return false
|
|
end
|
|
return true
|
|
end
|
|
|
|
def position
|
|
return 0 if @lastDrawnChar < 0
|
|
return @numtextchars if @lastDrawnChar >= @fmtchars.length
|
|
# index after the last character's index
|
|
return @fmtchars[@lastDrawnChar][14] + 1
|
|
end
|
|
|
|
def maxPosition
|
|
pos = 0
|
|
@fmtchars.each do |ch|
|
|
# index after the last character's index
|
|
pos = ch[14] + 1 if pos < ch[14] + 1
|
|
end
|
|
return pos
|
|
end
|
|
|
|
def skipAhead
|
|
return if !busy?
|
|
return if @textchars[@curchar] == "\n"
|
|
resume
|
|
if curcharSkip(true)
|
|
visiblelines = (self.height - self.borderY) / @lineHeight
|
|
if @textchars[@curchar] == "\n" && @linesdrawn >= visiblelines - 1
|
|
@scroll_timer_start = System.uptime
|
|
elsif @textchars[@curchar] == "\1"
|
|
@pausing = true if @curchar < @numtextchars - 1
|
|
self.startPause
|
|
refresh
|
|
end
|
|
end
|
|
end
|
|
|
|
def allocPause
|
|
return if @pausesprite
|
|
@pausesprite = AnimatedSprite.create("Graphics/UI/pause_arrow", 4, 3)
|
|
@pausesprite.z = 100000
|
|
@pausesprite.visible = false
|
|
end
|
|
|
|
def startPause
|
|
allocPause
|
|
@pausesprite.visible = true
|
|
@pausesprite.frame = 0
|
|
@pausesprite.start
|
|
moveCursor
|
|
end
|
|
|
|
def stopPause
|
|
return if !@pausesprite
|
|
@pausesprite.stop
|
|
@pausesprite.visible = false
|
|
end
|
|
|
|
def moveCursor
|
|
return if !@pausesprite
|
|
cursor = @cursorMode
|
|
cursor = 2 if cursor == 0 && !@endOfText
|
|
case cursor
|
|
when 0 # End of text
|
|
@pausesprite.x = self.x + self.startX + @endOfText.x + @endOfText.width - 2
|
|
@pausesprite.y = self.y + self.startY + @endOfText.y - @scrollY
|
|
when 1 # Lower right
|
|
pauseWidth = @pausesprite.bitmap ? @pausesprite.framewidth : 16
|
|
pauseHeight = @pausesprite.bitmap ? @pausesprite.frameheight : 16
|
|
@pausesprite.x = self.x + self.width - 40 + (pauseWidth / 2)
|
|
@pausesprite.y = self.y + self.height - 60 + (pauseHeight / 2)
|
|
when 2 # Lower middle
|
|
pauseWidth = @pausesprite.bitmap ? @pausesprite.framewidth : 16
|
|
pauseHeight = @pausesprite.bitmap ? @pausesprite.frameheight : 16
|
|
@pausesprite.x = self.x + (self.width / 2) - (pauseWidth / 2)
|
|
@pausesprite.y = self.y + self.height - 36 + (pauseHeight / 2)
|
|
end
|
|
end
|
|
|
|
def refresh
|
|
oldcontents = self.contents
|
|
self.contents = pbDoEnsureBitmap(oldcontents, @bitmapwidth, @bitmapheight)
|
|
self.oy = @scrollY
|
|
numchars = @numtextchars
|
|
numchars = [@curchar, @numtextchars].min if self.letterbyletter
|
|
return if busy? && @drawncurchar == @curchar && !@scroll_timer_start
|
|
if !self.letterbyletter || !oldcontents.equal?(self.contents)
|
|
@drawncurchar = -1
|
|
@needclear = true
|
|
end
|
|
if @needclear
|
|
self.contents.font = @oldfont if @oldfont
|
|
self.contents.clear
|
|
@needclear = false
|
|
end
|
|
if @nodraw
|
|
@nodraw = false
|
|
return
|
|
end
|
|
maxX = self.width - self.borderX
|
|
maxY = self.height - self.borderY
|
|
(@drawncurchar + 1..numchars).each do |i|
|
|
next if i >= @fmtchars.length
|
|
if !self.letterbyletter
|
|
next if @fmtchars[i][1] >= maxX
|
|
next if @fmtchars[i][2] >= maxY
|
|
end
|
|
drawSingleFormattedChar(self.contents, @fmtchars[i])
|
|
@lastDrawnChar = i
|
|
end
|
|
# all characters were drawn, reset old font
|
|
self.contents.font = @oldfont if !self.letterbyletter && @oldfont
|
|
if numchars > 0 && numchars != @numtextchars
|
|
fch = @fmtchars[numchars - 1]
|
|
if fch
|
|
rcdst = Rect.new(fch[1], fch[2], fch[3], fch[4])
|
|
if @textchars[numchars] == "\1"
|
|
@endOfText = rcdst
|
|
allocPause
|
|
moveCursor
|
|
else
|
|
@endOfText = Rect.new(rcdst.x + rcdst.width, rcdst.y, 8, 1)
|
|
end
|
|
end
|
|
end
|
|
@drawncurchar = @curchar
|
|
end
|
|
|
|
def redrawText
|
|
if @letterbyletter
|
|
oldPosition = self.position
|
|
self.text = self.text # Clears the text already drawn
|
|
oldPosition = @numtextchars if oldPosition > @numtextchars
|
|
while self.position != oldPosition
|
|
refresh
|
|
updateInternal
|
|
end
|
|
else
|
|
self.text = self.text
|
|
end
|
|
end
|
|
|
|
def updateInternal
|
|
time_now = System.uptime
|
|
@display_last_updated = time_now if !@display_last_updated
|
|
delta_t = time_now - @display_last_updated
|
|
@display_last_updated = time_now
|
|
visiblelines = (self.height - self.borderY) / @lineHeight
|
|
@lastchar = -1 if !@lastchar
|
|
show_more_characters = false
|
|
# Pauses and new lines
|
|
if @textchars[@curchar] == "\1" # Waiting
|
|
show_more_characters = true if !@pausing
|
|
elsif @textchars[@curchar] == "\n" # Move to new line
|
|
if @linesdrawn >= visiblelines - 1 # Need to scroll text to show new line
|
|
if @scroll_timer_start
|
|
old_y = @scrollstate
|
|
new_y = lerp(0, @lineHeight, 0.1, @scroll_timer_start, time_now)
|
|
@scrollstate = new_y
|
|
@scrollY += new_y - old_y
|
|
if @scrollstate >= @lineHeight
|
|
@scrollstate = 0
|
|
@scroll_timer_start = nil
|
|
@linesdrawn += 1
|
|
show_more_characters = true
|
|
end
|
|
else
|
|
show_more_characters = true
|
|
end
|
|
else # New line but the next line can be shown without scrolling to it
|
|
@linesdrawn += 1 if @lastchar < @curchar
|
|
show_more_characters = true
|
|
end
|
|
elsif @curchar <= @numtextchars # Displaying more text
|
|
show_more_characters = true
|
|
else
|
|
@displaying = false
|
|
@scrollstate = 0
|
|
@scrollY = 0
|
|
@scroll_timer_start = nil
|
|
@linesdrawn = 0
|
|
end
|
|
@lastchar = @curchar
|
|
# Keep displaying more text
|
|
if show_more_characters
|
|
@display_timer += delta_t
|
|
if curcharSkip
|
|
if @textchars[@curchar] == "\n" && @linesdrawn >= visiblelines - 1
|
|
@scroll_timer_start = time_now
|
|
elsif @textchars[@curchar] == "\1"
|
|
@pausing = true if @curchar < @numtextchars - 1
|
|
self.startPause
|
|
refresh
|
|
end
|
|
end
|
|
end
|
|
end
|
|
|
|
def update
|
|
super
|
|
@pausesprite.update if @pausesprite&.visible
|
|
if @wait_timer_start
|
|
if System.uptime - @wait_timer_start >= @waitcount
|
|
@wait_timer_start = nil
|
|
@waitcount = 0
|
|
@display_last_updated = nil
|
|
end
|
|
return if @wait_timer_start
|
|
end
|
|
if busy?
|
|
refresh if !@text_delay_changed
|
|
updateInternal
|
|
refresh if @text_delay_changed # Needed to allow "textspeed=0" to work seamlessly
|
|
end
|
|
@text_delay_changed = false
|
|
end
|
|
|
|
#-----------------------------------------------------------------------------
|
|
|
|
private
|
|
|
|
def curcharSkip(instant = false)
|
|
ret = false
|
|
loop do
|
|
break if @display_timer < @text_delay && !instant
|
|
@display_timer -= @text_delay if !instant
|
|
ret = true
|
|
@curchar += 1
|
|
break if @textchars[@curchar] == "\n" || # newline
|
|
@textchars[@curchar] == "\1" || # pause
|
|
@textchars[@curchar] == "\2" || # letter-by-letter break
|
|
@textchars[@curchar].nil?
|
|
end
|
|
return ret
|
|
end
|
|
end
|
|
|
|
#===============================================================================
|
|
#
|
|
#===============================================================================
|
|
class Window_InputNumberPokemon < SpriteWindow_Base
|
|
attr_reader :sign
|
|
|
|
def initialize(digits_max)
|
|
@digits_max = digits_max
|
|
@number = 0
|
|
@cursor_timer_start = System.uptime
|
|
@cursor_shown = true
|
|
@sign = false
|
|
@negative = false
|
|
super(0, 0, 32, 32)
|
|
self.width = (digits_max * 24) + 8 + self.borderX
|
|
self.height = 32 + self.borderY
|
|
colors = getDefaultTextColors(self.windowskin)
|
|
@baseColor = colors[0]
|
|
@shadowColor = colors[1]
|
|
@index = digits_max - 1
|
|
self.active = true
|
|
refresh
|
|
end
|
|
|
|
def active=(value)
|
|
super
|
|
refresh
|
|
end
|
|
|
|
def number
|
|
@number * (@sign && @negative ? -1 : 1)
|
|
end
|
|
|
|
def number=(value)
|
|
value = 0 if !value.is_a?(Numeric)
|
|
if @sign
|
|
@negative = (value < 0)
|
|
@number = [value.abs, (10**@digits_max) - 1].min
|
|
else
|
|
@number = [[value, 0].max, (10**@digits_max) - 1].min
|
|
end
|
|
refresh
|
|
end
|
|
|
|
def sign=(value)
|
|
@sign = value
|
|
self.width = (@digits_max * 24) + 8 + self.borderX + (@sign ? 24 : 0)
|
|
@index = (@digits_max - 1) + (@sign ? 1 : 0)
|
|
refresh
|
|
end
|
|
|
|
def refresh
|
|
self.contents = pbDoEnsureBitmap(self.contents,
|
|
self.width - self.borderX, self.height - self.borderY)
|
|
pbSetSystemFont(self.contents)
|
|
self.contents.clear
|
|
s = sprintf("%0*d", @digits_max, @number.abs)
|
|
if @sign
|
|
textHelper(0, 0, @negative ? "-" : "+", 0)
|
|
end
|
|
@digits_max.times do |i|
|
|
index = i + (@sign ? 1 : 0)
|
|
textHelper(index * 24, 0, s[i, 1], index)
|
|
end
|
|
end
|
|
|
|
def update
|
|
super
|
|
digits = @digits_max + (@sign ? 1 : 0)
|
|
cursor_to_show = ((System.uptime - @cursor_timer_start) / 0.35).to_i.even?
|
|
if cursor_to_show != @cursor_shown
|
|
@cursor_shown = cursor_to_show
|
|
refresh
|
|
end
|
|
if self.active
|
|
if Input.repeat?(Input::UP) || Input.repeat?(Input::DOWN)
|
|
pbPlayCursorSE
|
|
if @index == 0 && @sign
|
|
@negative = !@negative
|
|
else
|
|
place = 10**(digits - 1 - @index)
|
|
n = @number / place % 10
|
|
@number -= n * place
|
|
if Input.repeat?(Input::UP)
|
|
n = (n + 1) % 10
|
|
elsif Input.repeat?(Input::DOWN)
|
|
n = (n + 9) % 10
|
|
end
|
|
@number += n * place
|
|
end
|
|
refresh
|
|
elsif Input.repeat?(Input::RIGHT)
|
|
if digits >= 2
|
|
pbPlayCursorSE
|
|
@index = (@index + 1) % digits
|
|
@cursor_timer_start = System.uptime
|
|
@cursor_shown = true
|
|
refresh
|
|
end
|
|
elsif Input.repeat?(Input::LEFT)
|
|
if digits >= 2
|
|
pbPlayCursorSE
|
|
@index = (@index + digits - 1) % digits
|
|
@cursor_timer_start = System.uptime
|
|
@cursor_shown = true
|
|
refresh
|
|
end
|
|
end
|
|
end
|
|
end
|
|
|
|
#-----------------------------------------------------------------------------
|
|
|
|
private
|
|
|
|
def textHelper(x, y, text, i)
|
|
textwidth = self.contents.text_size(text).width
|
|
pbDrawShadowText(self.contents,
|
|
x + (12 - (textwidth / 2)),
|
|
y - 2 + (self.contents.text_offset_y || 0), # TEXT OFFSET (the - 2)
|
|
textwidth + 4, 32, text, @baseColor, @shadowColor)
|
|
# Draw cursor
|
|
if @index == i && @active && @cursor_shown
|
|
self.contents.fill_rect(x + (12 - (textwidth / 2)), y + 28, textwidth, 4, @shadowColor)
|
|
self.contents.fill_rect(x + (12 - (textwidth / 2)), y + 28, textwidth - 2, 2, @baseColor)
|
|
end
|
|
end
|
|
end
|
|
|
|
#===============================================================================
|
|
#
|
|
#===============================================================================
|
|
class SpriteWindow_Selectable < SpriteWindow_Base
|
|
attr_reader :index
|
|
attr_writer :ignore_input
|
|
|
|
def initialize(x, y, width, height)
|
|
super(x, y, width, height)
|
|
@item_max = 1
|
|
@column_max = 1
|
|
@virtualOy = 2 # TEXT OFFSET
|
|
@index = -1
|
|
@row_height = 32
|
|
@column_spacing = 32
|
|
@ignore_input = false
|
|
end
|
|
|
|
def itemCount
|
|
return @item_max || 0
|
|
end
|
|
|
|
def index=(index)
|
|
if @index != index
|
|
@index = index
|
|
priv_update_cursor_rect(true)
|
|
end
|
|
end
|
|
|
|
def rowHeight
|
|
return @row_height || 32
|
|
end
|
|
|
|
def rowHeight=(value)
|
|
if @row_height != value
|
|
oldTopRow = self.top_row
|
|
@row_height = [1, value].max
|
|
self.top_row = oldTopRow
|
|
update_cursor_rect
|
|
end
|
|
end
|
|
|
|
def columns
|
|
return @column_max || 1
|
|
end
|
|
|
|
def columns=(value)
|
|
if @column_max != value
|
|
@column_max = [1, value].max
|
|
update_cursor_rect
|
|
end
|
|
end
|
|
|
|
def columnSpacing
|
|
return @column_spacing || 32
|
|
end
|
|
|
|
def columnSpacing=(value)
|
|
if @column_spacing != value
|
|
@column_spacing = [0, value].max
|
|
update_cursor_rect
|
|
end
|
|
end
|
|
|
|
def count
|
|
return @item_max
|
|
end
|
|
|
|
def row_max
|
|
return ((@item_max + @column_max - 1) / @column_max).to_i
|
|
end
|
|
|
|
def top_row
|
|
return (@virtualOy / (@row_height || 32)).to_i
|
|
end
|
|
|
|
def top_row=(row)
|
|
row = row_max - 1 if row > row_max - 1
|
|
row = 0 if row < 0
|
|
@virtualOy = (row * @row_height) + 2 # TEXT OFFSET (the + 2)
|
|
end
|
|
|
|
def top_item
|
|
return top_row * @column_max
|
|
end
|
|
|
|
def page_row_max
|
|
return priv_page_row_max.to_i
|
|
end
|
|
|
|
def page_item_max
|
|
return priv_page_item_max.to_i
|
|
end
|
|
|
|
def itemRect(item)
|
|
if item < 0 || item >= @item_max || item < self.top_item ||
|
|
item > self.top_item + self.page_item_max
|
|
return Rect.new(0, 0, 0, 0)
|
|
else
|
|
cursor_width = (self.width - self.borderX - ((@column_max - 1) * @column_spacing)) / @column_max
|
|
x = item % @column_max * (cursor_width + @column_spacing)
|
|
y = (item / @column_max * @row_height) - @virtualOy
|
|
return Rect.new(x, y, cursor_width, @row_height)
|
|
end
|
|
end
|
|
|
|
def refresh; end
|
|
|
|
def update_cursor_rect
|
|
priv_update_cursor_rect
|
|
end
|
|
|
|
def update
|
|
super
|
|
if self.active && @item_max > 0 && @index >= 0 && !@ignore_input
|
|
if Input.repeat?(Input::UP)
|
|
if @index >= @column_max ||
|
|
(Input.trigger?(Input::UP) && (@item_max % @column_max) == 0)
|
|
oldindex = @index
|
|
@index = (@index - @column_max + @item_max) % @item_max
|
|
if @index != oldindex
|
|
pbPlayCursorSE
|
|
update_cursor_rect
|
|
end
|
|
end
|
|
elsif Input.repeat?(Input::DOWN)
|
|
if @index < @item_max - @column_max ||
|
|
(Input.trigger?(Input::DOWN) && (@item_max % @column_max) == 0)
|
|
oldindex = @index
|
|
@index = (@index + @column_max) % @item_max
|
|
if @index != oldindex
|
|
pbPlayCursorSE
|
|
update_cursor_rect
|
|
end
|
|
end
|
|
elsif Input.repeat?(Input::LEFT)
|
|
if @column_max >= 2 && @index > 0
|
|
oldindex = @index
|
|
@index -= 1
|
|
if @index != oldindex
|
|
pbPlayCursorSE
|
|
update_cursor_rect
|
|
end
|
|
end
|
|
elsif Input.repeat?(Input::RIGHT)
|
|
if @column_max >= 2 && @index < @item_max - 1
|
|
oldindex = @index
|
|
@index += 1
|
|
if @index != oldindex
|
|
pbPlayCursorSE
|
|
update_cursor_rect
|
|
end
|
|
end
|
|
elsif Input.repeat?(Input::JUMPUP)
|
|
if @index > 0
|
|
oldindex = @index
|
|
@index = [self.index - self.page_item_max, 0].max
|
|
if @index != oldindex
|
|
pbPlayCursorSE
|
|
self.top_row -= self.page_row_max
|
|
update_cursor_rect
|
|
end
|
|
end
|
|
elsif Input.repeat?(Input::JUMPDOWN)
|
|
if @index < @item_max - 1
|
|
oldindex = @index
|
|
@index = [self.index + self.page_item_max, @item_max - 1].min
|
|
if @index != oldindex
|
|
pbPlayCursorSE
|
|
self.top_row += self.page_row_max
|
|
update_cursor_rect
|
|
end
|
|
end
|
|
end
|
|
end
|
|
end
|
|
|
|
#-----------------------------------------------------------------------------
|
|
|
|
private
|
|
|
|
def priv_page_row_max
|
|
return (self.height - self.borderY) / @row_height
|
|
end
|
|
|
|
def priv_page_item_max
|
|
return (self.height - self.borderY) / @row_height * @column_max
|
|
end
|
|
|
|
def priv_update_cursor_rect(force = false)
|
|
if @index < 0
|
|
self.cursor_rect.empty
|
|
self.refresh
|
|
return
|
|
end
|
|
dorefresh = false
|
|
row = @index / @column_max
|
|
# This code makes lists scroll only when the cursor hits the top and bottom
|
|
# of the visible list.
|
|
# if row < self.top_row
|
|
# self.top_row = row
|
|
# dorefresh=true
|
|
# end
|
|
# if row > self.top_row + (self.page_row_max - 1)
|
|
# self.top_row = row - (self.page_row_max - 1)
|
|
# dorefresh=true
|
|
# end
|
|
# if oldindex-self.top_item>=((self.page_item_max - 1)/2)
|
|
# self.top_row+=1
|
|
# end
|
|
# self.top_row = [self.top_row, self.row_max - self.page_row_max].min
|
|
# This code makes the cursor stay in the middle of the visible list as much
|
|
# as possible.
|
|
new_top_row = row - ((self.page_row_max - 1) / 2).floor
|
|
new_top_row = [[new_top_row, self.row_max - self.page_row_max].min, 0].max
|
|
if self.top_row != new_top_row
|
|
self.top_row = new_top_row
|
|
# dorefresh = true
|
|
end
|
|
# End of code
|
|
cursor_width = (self.width - self.borderX) / @column_max
|
|
x = self.index % @column_max * (cursor_width + @column_spacing)
|
|
y = (self.index / @column_max * @row_height) - @virtualOy
|
|
self.cursor_rect.set(x, y, cursor_width, @row_height)
|
|
self.refresh if dorefresh || force
|
|
end
|
|
end
|
|
|
|
#===============================================================================
|
|
#
|
|
#===============================================================================
|
|
module UpDownArrowMixin
|
|
def initUpDownArrow
|
|
@uparrow = AnimatedSprite.create("Graphics/UI/up_arrow", 8, 2, self.viewport)
|
|
@downarrow = AnimatedSprite.create("Graphics/UI/down_arrow", 8, 2, self.viewport)
|
|
RPG::Cache.retain("Graphics/UI/up_arrow")
|
|
RPG::Cache.retain("Graphics/UI/down_arrow")
|
|
@uparrow.z = 99998
|
|
@downarrow.z = 99998
|
|
@uparrow.visible = false
|
|
@downarrow.visible = false
|
|
@uparrow.play
|
|
@downarrow.play
|
|
end
|
|
|
|
def dispose
|
|
@uparrow.dispose
|
|
@downarrow.dispose
|
|
super
|
|
end
|
|
|
|
def viewport=(value)
|
|
super
|
|
@uparrow.viewport = self.viewport
|
|
@downarrow.viewport = self.viewport
|
|
end
|
|
|
|
def color=(value)
|
|
super
|
|
@uparrow.color = value
|
|
@downarrow.color = value
|
|
end
|
|
|
|
def adjustForZoom(sprite)
|
|
sprite.zoom_x = self.zoom_x
|
|
sprite.zoom_y = self.zoom_y
|
|
sprite.x = (sprite.x * self.zoom_x) + (self.offset_x / self.zoom_x)
|
|
sprite.y = (sprite.y * self.zoom_y) + (self.offset_y / self.zoom_y)
|
|
end
|
|
|
|
def update
|
|
super
|
|
@uparrow.x = self.x + (self.width / 2) - (@uparrow.framewidth / 2)
|
|
@downarrow.x = self.x + (self.width / 2) - (@downarrow.framewidth / 2)
|
|
@uparrow.y = self.y
|
|
@downarrow.y = self.y + self.height - @downarrow.frameheight
|
|
@uparrow.visible = self.visible && self.active && (self.top_item != 0 &&
|
|
@item_max > self.page_item_max)
|
|
@downarrow.visible = self.visible && self.active &&
|
|
(self.top_item + self.page_item_max < @item_max && @item_max > self.page_item_max)
|
|
@uparrow.z = self.z + 1
|
|
@downarrow.z = self.z + 1
|
|
adjustForZoom(@uparrow)
|
|
adjustForZoom(@downarrow)
|
|
@uparrow.viewport = self.viewport
|
|
@downarrow.viewport = self.viewport
|
|
@uparrow.update
|
|
@downarrow.update
|
|
end
|
|
end
|
|
|
|
#===============================================================================
|
|
#
|
|
#===============================================================================
|
|
class SpriteWindow_SelectableEx < SpriteWindow_Selectable
|
|
include UpDownArrowMixin
|
|
|
|
def initialize(*arg)
|
|
super(*arg)
|
|
initUpDownArrow
|
|
end
|
|
end
|
|
|
|
#===============================================================================
|
|
#
|
|
#===============================================================================
|
|
class Window_DrawableCommand < SpriteWindow_SelectableEx
|
|
attr_reader :baseColor
|
|
attr_reader :shadowColor
|
|
|
|
def initialize(x, y, width, height, viewport = nil)
|
|
super(x, y, width, height)
|
|
self.viewport = viewport if viewport
|
|
if isDarkWindowskin(self.windowskin)
|
|
@selarrow = AnimatedBitmap.new("Graphics/UI/sel_arrow_white")
|
|
RPG::Cache.retain("Graphics/UI/sel_arrow_white")
|
|
else
|
|
@selarrow = AnimatedBitmap.new("Graphics/UI/sel_arrow")
|
|
RPG::Cache.retain("Graphics/UI/sel_arrow")
|
|
end
|
|
@index = 0
|
|
colors = getDefaultTextColors(self.windowskin)
|
|
@baseColor = colors[0]
|
|
@shadowColor = colors[1]
|
|
refresh
|
|
end
|
|
|
|
def dispose
|
|
@selarrow.dispose
|
|
super
|
|
end
|
|
|
|
def baseColor=(value)
|
|
@baseColor = value
|
|
refresh
|
|
end
|
|
|
|
def shadowColor=(value)
|
|
@shadowColor = value
|
|
refresh
|
|
end
|
|
|
|
def textWidth(bitmap, text)
|
|
return bitmap.text_size(text).width
|
|
end
|
|
|
|
def getAutoDims(commands, dims, width = nil)
|
|
rowMax = ((commands.length + self.columns - 1) / self.columns).to_i
|
|
windowheight = (rowMax * self.rowHeight)
|
|
windowheight += self.borderY
|
|
if !width || width < 0
|
|
width = 0
|
|
tmpbitmap = Bitmap.new(1, 1)
|
|
pbSetSystemFont(tmpbitmap)
|
|
commands.each do |i|
|
|
width = [width, tmpbitmap.text_size(i).width].max
|
|
end
|
|
# one 16 to allow cursor
|
|
width += 16 + 16 + SpriteWindow_Base::TEXT_PADDING
|
|
tmpbitmap.dispose
|
|
end
|
|
# Store suggested width and height of window
|
|
dims[0] = [self.borderX + 1,
|
|
(width * self.columns) + self.borderX + ((self.columns - 1) * self.columnSpacing)].max
|
|
dims[1] = [self.borderY + 1, windowheight].max
|
|
dims[1] = [dims[1], Graphics.height].min
|
|
end
|
|
|
|
def setSkin(skin)
|
|
super(skin)
|
|
privRefresh(true)
|
|
colors = getDefaultTextColors(self.windowskin)
|
|
@baseColor = colors[0]
|
|
@shadowColor = colors[1]
|
|
end
|
|
|
|
def drawCursor(index, rect)
|
|
if self.index == index
|
|
pbCopyBitmap(self.contents, @selarrow.bitmap, rect.x, rect.y + 2) # TEXT OFFSET (counters the offset above)
|
|
end
|
|
return Rect.new(rect.x + 16, rect.y, rect.width - 16, rect.height)
|
|
end
|
|
|
|
# To be implemented by derived classes.
|
|
def itemCount
|
|
return 0
|
|
end
|
|
|
|
# To be implemented by derived classes.
|
|
def drawItem(index, count, rect); end
|
|
|
|
def refresh
|
|
@item_max = itemCount
|
|
dwidth = self.width - self.borderX
|
|
dheight = self.height - self.borderY
|
|
self.contents = pbDoEnsureBitmap(self.contents, dwidth, dheight)
|
|
self.contents.clear
|
|
@item_max.times do |i|
|
|
next if i < self.top_item || i > self.top_item + self.page_item_max
|
|
drawItem(i, @item_max, itemRect(i))
|
|
end
|
|
end
|
|
|
|
def update
|
|
oldindex = self.index
|
|
super
|
|
refresh if self.index != oldindex
|
|
end
|
|
end
|
|
|
|
#===============================================================================
|
|
#
|
|
#===============================================================================
|
|
class Window_CommandPokemon < Window_DrawableCommand
|
|
attr_reader :commands
|
|
|
|
def initialize(commands, width = nil)
|
|
@starting = true
|
|
@commands = []
|
|
dims = []
|
|
super(0, 0, 32, 32)
|
|
getAutoDims(commands, dims, width)
|
|
self.width = dims[0]
|
|
self.height = dims[1]
|
|
@commands = commands
|
|
self.active = true
|
|
colors = getDefaultTextColors(self.windowskin)
|
|
self.baseColor = colors[0]
|
|
self.shadowColor = colors[1]
|
|
refresh
|
|
@starting = false
|
|
end
|
|
|
|
def self.newWithSize(commands, x, y, width, height, viewport = nil)
|
|
ret = self.new(commands, width)
|
|
ret.x = x
|
|
ret.y = y
|
|
ret.width = width
|
|
ret.height = height
|
|
ret.viewport = viewport
|
|
return ret
|
|
end
|
|
|
|
def self.newEmpty(x, y, width, height, viewport = nil)
|
|
ret = self.new([], width)
|
|
ret.x = x
|
|
ret.y = y
|
|
ret.width = width
|
|
ret.height = height
|
|
ret.viewport = viewport
|
|
return ret
|
|
end
|
|
|
|
def index=(value)
|
|
super
|
|
refresh if !@starting
|
|
end
|
|
|
|
def commands=(value)
|
|
@commands = value
|
|
@item_max = commands.length
|
|
self.update_cursor_rect
|
|
self.refresh
|
|
end
|
|
|
|
def width=(value)
|
|
super
|
|
if !@starting
|
|
self.index = self.index
|
|
self.update_cursor_rect
|
|
end
|
|
end
|
|
|
|
def height=(value)
|
|
super
|
|
if !@starting
|
|
self.index = self.index
|
|
self.update_cursor_rect
|
|
end
|
|
end
|
|
|
|
def resizeToFit(commands, width = nil)
|
|
dims = []
|
|
getAutoDims(commands, dims, width)
|
|
self.width = dims[0]
|
|
self.height = dims[1]
|
|
end
|
|
|
|
def itemCount
|
|
return @commands ? @commands.length : 0
|
|
end
|
|
|
|
def drawItem(index, _count, rect)
|
|
pbSetSystemFont(self.contents) if @starting
|
|
rect = drawCursor(index, rect)
|
|
pbDrawShadowText(self.contents, rect.x, rect.y + (self.contents.text_offset_y || 0),
|
|
rect.width, rect.height, @commands[index], self.baseColor, self.shadowColor)
|
|
end
|
|
end
|
|
|
|
#===============================================================================
|
|
#
|
|
#===============================================================================
|
|
class Window_CommandPokemonEx < Window_CommandPokemon
|
|
end
|
|
|
|
#===============================================================================
|
|
#
|
|
#===============================================================================
|
|
class Window_AdvancedCommandPokemon < Window_DrawableCommand
|
|
attr_reader :commands
|
|
|
|
def textWidth(bitmap, text)
|
|
dims = [nil, 0]
|
|
chars = getFormattedText(bitmap, 0, 0,
|
|
Graphics.width - self.borderX - SpriteWindow_Base::TEXT_PADDING - 16,
|
|
-1, text, self.rowHeight, true, true)
|
|
chars.each do |ch|
|
|
dims[0] = dims[0] ? [dims[0], ch[1]].min : ch[1]
|
|
dims[1] = [dims[1], ch[1] + ch[3]].max
|
|
end
|
|
dims[0] = 0 if !dims[0]
|
|
return dims[1] - dims[0]
|
|
end
|
|
|
|
def initialize(commands, width = nil)
|
|
@starting = true
|
|
@commands = []
|
|
dims = []
|
|
super(0, 0, 32, 32)
|
|
getAutoDims(commands, dims, width)
|
|
self.width = dims[0]
|
|
self.height = dims[1]
|
|
@commands = commands
|
|
self.active = true
|
|
colors = getDefaultTextColors(self.windowskin)
|
|
self.baseColor = colors[0]
|
|
self.shadowColor = colors[1]
|
|
refresh
|
|
@starting = false
|
|
end
|
|
|
|
def self.newWithSize(commands, x, y, width, height, viewport = nil)
|
|
ret = self.new(commands, width)
|
|
ret.x = x
|
|
ret.y = y
|
|
ret.width = width
|
|
ret.height = height
|
|
ret.viewport = viewport
|
|
return ret
|
|
end
|
|
|
|
def self.newEmpty(x, y, width, height, viewport = nil)
|
|
ret = self.new([], width)
|
|
ret.x = x
|
|
ret.y = y
|
|
ret.width = width
|
|
ret.height = height
|
|
ret.viewport = viewport
|
|
return ret
|
|
end
|
|
|
|
def index=(value)
|
|
super
|
|
refresh if !@starting
|
|
end
|
|
|
|
def commands=(value)
|
|
@commands = value
|
|
@item_max = commands.length
|
|
self.update_cursor_rect
|
|
self.refresh
|
|
end
|
|
|
|
def width=(value)
|
|
oldvalue = self.width
|
|
super
|
|
if !@starting && oldvalue != value
|
|
self.index = self.index
|
|
self.update_cursor_rect
|
|
end
|
|
end
|
|
|
|
def height=(value)
|
|
oldvalue = self.height
|
|
super
|
|
if !@starting && oldvalue != value
|
|
self.index = self.index
|
|
self.update_cursor_rect
|
|
end
|
|
end
|
|
|
|
def resizeToFit(commands, width = nil)
|
|
dims = []
|
|
getAutoDims(commands, dims, width)
|
|
self.width = dims[0]
|
|
self.height = dims[1] - 6
|
|
end
|
|
|
|
def itemCount
|
|
return @commands ? @commands.length : 0
|
|
end
|
|
|
|
def drawItem(index, _count, rect)
|
|
pbSetSystemFont(self.contents)
|
|
rect = drawCursor(index, rect)
|
|
if toUnformattedText(@commands[index]).gsub(/\n/, "") == @commands[index]
|
|
# Use faster alternative for unformatted text without line breaks
|
|
pbDrawShadowText(self.contents, rect.x, rect.y + (self.contents.text_offset_y || 0),
|
|
rect.width, rect.height, @commands[index], self.baseColor, self.shadowColor)
|
|
else
|
|
chars = getFormattedText(self.contents, rect.x, rect.y + (self.contents.text_offset_y || 0),
|
|
rect.width, rect.height, @commands[index], rect.height, true, true)
|
|
drawFormattedChars(self.contents, chars)
|
|
end
|
|
end
|
|
end
|
|
|
|
#===============================================================================
|
|
#
|
|
#===============================================================================
|
|
class Window_AdvancedCommandPokemonEx < Window_AdvancedCommandPokemon
|
|
end
|