#=============================================================================== # Text colours #=============================================================================== def ctag(color) ret = (color.red.to_i << 24) ret |= ((color.green.to_i) << 16) ret |= ((color.blue.to_i) << 8) ret |= ((color.alpha.to_i)) return sprintf("", ret) end def shadowctag(base, shadow) return sprintf("", colorToRgb16(base), colorToRgb16(shadow)) end def shadowc3tag(base, shadow) return sprintf("", colorToRgb32(base), colorToRgb32(shadow)) end def shadowctagFromColor(color) return shadowc3tag(color, getContrastColor(color)) end def shadowctagFromRgb(param) return shadowctagFromColor(rgbToColor(param)) end def colorToRgb32(color) return "" if !color if color.alpha.to_i == 255 return sprintf("%02X%02X%02X", color.red.to_i, color.green.to_i, color.blue.to_i) else return sprintf("%02X%02X%02X%02X", color.red.to_i, color.green.to_i, color.blue.to_i, color.alpha.to_i) end end def colorToRgb16(color) ret = (color.red.to_i >> 3) ret |= ((color.green.to_i >> 3) << 5) ret |= ((color.blue.to_i >> 3) << 10) return sprintf("%04X", ret) end def rgbToColor(param) return Font.default_color if !param baseint = param.to_i(16) case param.length when 8 # 32-bit hex return Color.new( (baseint >> 24) & 0xFF, (baseint >> 16) & 0xFF, (baseint >> 8) & 0xFF, (baseint) & 0xFF ) when 6 # 24-bit hex return Color.new( (baseint >> 16) & 0xFF, (baseint >> 8) & 0xFF, (baseint) & 0xFF ) when 4 # 16-bit hex return Color.new( ((baseint) & 0x1F) << 3, ((baseint >> 5) & 0x1F) << 3, ((baseint >> 10) & 0x1F) << 3 ) when 1 # Color number i = param.to_i return Font.default_color if i >= 8 return [ Color.new(255, 255, 255, 255), Color.new(128, 128, 255, 255), Color.new(255, 128, 128, 255), Color.new(128, 255, 128, 255), Color.new(128, 255, 255, 255), Color.new(255, 128, 255, 255), Color.new(255, 255, 128, 255), Color.new(192, 192, 192, 255) ][i] else return Font.default_color end end def Rgb16ToColor(param) baseint = param.to_i(16) return Color.new( ((baseint) & 0x1F) << 3, ((baseint >> 5) & 0x1F) << 3, ((baseint >> 10) & 0x1F) << 3 ) end def getContrastColor(color) raise "No color given" if !color r = color.red g = color.green b = color.blue yuv = [ r * 0.299 + g * 0.587 + b * 0.114, r * -0.1687 + g * -0.3313 + b * 0.500 + 0.5, r * 0.500 + g * -0.4187 + b * -0.0813 + 0.5 ] if yuv[0] < 127.5 yuv[0] += (255 - yuv[0]) / 2 else yuv[0] = yuv[0] / 2 end return Color.new( yuv[0] + 1.4075 * (yuv[2] - 0.5), yuv[0] - 0.3455 * (yuv[1] - 0.5) - 0.7169 * (yuv[2] - 0.5), yuv[0] + 1.7790 * (yuv[1] - 0.5), color.alpha ) end #=============================================================================== # Format text #=============================================================================== FORMATREGEXP = /<(\/?)(c|c2|c3|o|fn|br|fs|i|b|r|pg|pog|u|s|icon|img|ac|ar|al|outln|outln2)(\s*\=\s*([^>]*))?>/i def fmtescape(text) if text[/[&<>]/] text2 = text.gsub(/&/, "&") text2.gsub!(//, ">") return text2 end return text end def toUnformattedText(text) text2 = text.gsub(FORMATREGEXP, "") text2.gsub!(/</, "<") text2.gsub!(/>/, ">") text2.gsub!(/'/, "'") text2.gsub!(/"/, "\"") text2.gsub!(/&/, "&") return text2 end def unformattedTextLength(text) return toUnformattedText(text).scan(/./m).length end def itemIconTag(item) return "" if !item if item.respond_to?("icon_name") return sprintf("", item.icon_name) else ix = item.icon_index % 16 * 24 iy = item.icon_index / 16 * 24 return sprintf("", ix, iy) end end def getFormattedTextForDims(bitmap, xDst, yDst, widthDst, heightDst, text, lineheight, newlineBreaks = true, explicitBreaksOnly = false) text2 = text.gsub(/<(\/?)(c|c2|c3|o|u|s)(\s*\=\s*([^>]*))?>/i, "") if newlineBreaks text2.gsub!(/<(\/?)(br)(\s*\=\s*([^>]*))?>/i, "\n") end return getFormattedText(bitmap, xDst, yDst, widthDst, heightDst, text2, lineheight, newlineBreaks, explicitBreaksOnly, true) end def getFormattedTextFast(bitmap, xDst, yDst, widthDst, heightDst, text, lineheight, newlineBreaks = true, explicitBreaksOnly = false) x = y = 0 characters = [] textchunks = [] textchunks.push(text) text = textchunks.join("") textchars = text.scan(/./m) lastword = [0, 0] # position of last word hadspace = false hadnonspace = false bold = bitmap.font.bold italic = bitmap.font.italic colorclone = bitmap.font.color defaultfontname = bitmap.font.name if defaultfontname.is_a?(Array) defaultfontname = defaultfontname.find { |i| Font.exist?(i) } || "Arial" elsif !Font.exist?(defaultfontname) defaultfontname = "Arial" end defaultfontname = defaultfontname.clone havenl = false position = 0 while position < textchars.length yStart = 0 xStart = 0 width = isWaitChar(textchars[position]) ? 0 : bitmap.text_size(textchars[position]).width if textchars[position] == "\n" if newlineBreaks # treat newline as break havenl = true characters.push(["\n", x, y * lineheight + yDst, 0, lineheight, false, false, false, colorclone, nil, false, false, "", 8, position, nil, 0]) y += 1 x = 0 hadspace = true hadnonspace = false position += 1 next else # treat newline as space textchars[position] = " " end end isspace = (textchars[position][/\s/] || isWaitChar(textchars[position])) ? true : false if hadspace && !isspace # set last word to here lastword[0] = characters.length lastword[1] = x hadspace = false hadnonspace = true elsif isspace hadspace = true end texty = (lineheight * y) + yDst + yStart # Push character if heightDst < 0 || yStart < yDst + heightDst havenl = true if isWaitChar(textchars[position]) characters.push([ textchars[position], x + xStart, texty, width + 2, lineheight, false, bold, italic, colorclone, nil, false, false, defaultfontname, bitmap.font.size, position, nil, 0 ]) end x += width if !explicitBreaksOnly && x + 2 > widthDst && lastword[1] != 0 && (!hadnonspace || !hadspace) havenl = true characters.insert(lastword[0], ["\n", x, y * lineheight + yDst, 0, lineheight, false, false, false, colorclone, nil, false, false, "", 8, position]) lastword[0] += 1 y += 1 x = 0 for i in lastword[0]...characters.length characters[i][2] += lineheight charwidth = characters[i][3] - 2 characters[i][1] = x x += charwidth end lastword[1] = 0 end position += 1 end # Eliminate spaces before newlines and pause character if havenl firstspace = -1 for i in 0...characters.length if characters[i][5] != false # If not a character firstspace = -1 elsif (characters[i][0] == "\n" || isWaitChar(characters[i][0])) && firstspace >= 0 for j in firstspace...i characters[j] = nil end firstspace = -1 elsif characters[i][0][/[ \r\t]/] firstspace = i if firstspace < 0 else firstspace = -1 end end if firstspace > 0 for j in firstspace...characters.length characters[j] = nil end end characters.compact! end for i in 0...characters.length characters[i][1] = xDst + characters[i][1] end # Remove all characters with Y greater or equal to _yDst_+_heightDst_ if heightDst >= 0 for i in 0...characters.length if characters[i][2] >= yDst + heightDst characters[i] = nil end end characters.compact! end return characters end def isWaitChar(x) return (["\001", "\002"].include?(x)) end def getLastParam(array, default) i = array.length - 1 while i >= 0 return array[i] if array[i] i -= 1 end return default end def getLastColors(colorstack, opacitystack, defaultcolors) colors = getLastParam(colorstack, defaultcolors) opacity = getLastParam(opacitystack, 255) if opacity != 255 colors = [ Color.new(colors[0].red, colors[0].green, colors[0].blue, colors[0].alpha * opacity / 255), colors[1] ? Color.new(colors[1].red, colors[1].green, colors[1].blue, colors[1].alpha * opacity / 255) : nil ] end return colors end #=============================================================================== # Formats a string of text and returns an array containing a list of formatted # characters. #=============================================================================== =begin Parameters: bitmap: Source bitmap. Will be used to determine the default font of the text. xDst: X coordinate of the text's top left corner. yDst: Y coordinate of the text's top left corner. widthDst: Width of the text. Used to determine line breaks. heightDst: Height of the text. If -1, there is no height restriction. If 1 or greater, any characters exceeding the height are removed from the returned list. newLineBreaks: If true, newline characters will be treated as line breaks. The default is true. Return Values: A list of formatted characters. Returns an empty array if _bitmap_ is nil or disposed, or if _widthDst_ is 0 or less or _heightDst_ is 0. Formatting Specification: This function uses the following syntax when formatting the text. ... - Formats the text in bold. ... - Formats the text in italics. ... - Underlines the text. ... - Draws a strikeout line over the text. ... - Left-aligns the text. Causes line breaks before and after the text. - Right-aligns the text until the next line break. ... - Right-aligns the text. Causes line breaks before and after the text. ... - Centers the text. Causes line breaks before and after the text.
- Causes a line break. ... - Color specification. A total of four formats are supported: RRGGBBAA, RRGGBB, 16-bit RGB, and Window_Base color numbers. ... - Color specification where the first half is the base color and the second half is the shadow color. 16-bit RGB is supported. Added 2009-10-20 ... - Color specification where B is the base color and S is the shadow color. B and/or S can be omitted. A total of four formats are supported: RRGGBBAA, RRGGBB, 16-bit RGB, and Window_Base color numbers. Added 2009-9-12 - Displays the text in the given opacity (0-255) Added 2009-10-19 - Displays the text in outline format. Added 2010-05-12 - Displays the text in outline format (outlines more exaggerated. ... - Formats the text in the specified font, or Arial if the font doesn't exist. ... - Changes the font size to X. - Displays the icon X (in Graphics/Icons/). In addition, the syntax supports the following: ' - Converted to "'". < - Converted to "<". > - Converted to ">". & - Converted to "&". " - Converted to double quotation mark. To draw the characters, pass the returned array to the _drawFormattedChars_ function. =end def getFormattedText(bitmap, xDst, yDst, widthDst, heightDst, text, lineheight = 32, newlineBreaks = true, explicitBreaksOnly = false, collapseAlignments = false) dummybitmap = nil if !bitmap || bitmap.disposed? # allows function to be called with nil bitmap dummybitmap = Bitmap.new(1, 1) bitmap = dummybitmap return end if !bitmap || bitmap.disposed? || widthDst <= 0 || heightDst == 0 || text.length == 0 return [] end textchunks = [] controls = [] oldtext = text while text[FORMATREGEXP] textchunks.push($~.pre_match) if $~[3] controls.push([$~[2].downcase, $~[4], -1, $~[1] == "/"]) else controls.push([$~[2].downcase, "", -1, $~[1] == "/"]) end text = $~.post_match end if controls.length == 0 ret = getFormattedTextFast(bitmap, xDst, yDst, widthDst, heightDst, text, lineheight, newlineBreaks, explicitBreaksOnly) dummybitmap.dispose if dummybitmap return ret end x = y = 0 characters = [] charactersInternal = [] # realtext = nil # realtextStart = "" # if !explicitBreaksOnly && textchunks.join("").length == 0 # # All commands occurred at the beginning of the text string # realtext = (newlineBreaks) ? text : text.gsub(/\n/, " ") # realtextStart = oldtext[0, oldtext.length - realtext.length] # end textchunks.push(text) for chunk in textchunks chunk.gsub!(/</, "<") chunk.gsub!(/>/, ">") chunk.gsub!(/'/, "'") chunk.gsub!(/"/, "\"") chunk.gsub!(/&/, "&") end textlen = 0 for i in 0...controls.length textlen += textchunks[i].scan(/./m).length controls[i][2] = textlen end text = textchunks.join("") textchars = text.scan(/./m) colorstack = [] boldcount = 0 italiccount = 0 outlinecount = 0 underlinecount = 0 strikecount = 0 rightalign = 0 outline2count = 0 opacitystack = [] oldfont = bitmap.font.clone defaultfontname = bitmap.font.name defaultfontsize = bitmap.font.size fontsize = defaultfontsize fontnamestack = [] fontsizestack = [] defaultcolors = [oldfont.color.clone, nil] if defaultfontname.is_a?(Array) defaultfontname = defaultfontname.find { |i| Font.exist?(i) } || "Arial" elsif !Font.exist?(defaultfontname) defaultfontname = "Arial" end defaultfontname = defaultfontname.clone fontname = defaultfontname alignstack = [] lastword = [0, 0] # position of last word hadspace = false hadnonspace = false havenl = false position = 0 while position < textchars.length nextline = 0 graphic = nil graphicX = 0 graphicY = 4 graphicWidth = nil graphicHeight = nil graphicRect = nil for i in 0...controls.length if controls[i] && controls[i][2] == position control = controls[i][0] param = controls[i][1] endtag = controls[i][3] case control when "c" if endtag colorstack.pop else color = rgbToColor(param) colorstack.push([color, nil]) end when "c2" if endtag colorstack.pop else base = Rgb16ToColor(param[0, 4]) shadow = Rgb16ToColor(param[4, 4]) colorstack.push([base, shadow]) end when "c3" if endtag colorstack.pop else param = param.split(",") # get pure colors unaffected by opacity oldColors = getLastParam(colorstack, defaultcolors) base = (param[0] && param[0] != "") ? rgbToColor(param[0]) : oldColors[0] shadow = (param[1] && param[1] != "") ? rgbToColor(param[1]) : oldColors[1] colorstack.push([base, shadow]) end when "o" if endtag opacitystack.pop else opacitystack.push(param.sub(/\s+$/, "").to_i) end when "b" boldcount += (endtag ? -1 : 1) when "i" italiccount += (endtag ? -1 : 1) when "u" underlinecount += (endtag ? -1 : 1) when "s" strikecount += (endtag ? -1 : 1) when "outln" outlinecount += (endtag ? -1 : 1) when "outln2" outline2count += (endtag ? -1 : 1) when "fs" # Font size if endtag fontsizestack.pop else fontsizestack.push(param.sub(/\s+$/, "").to_i) end fontsize = getLastParam(fontsizestack, defaultfontsize) bitmap.font.size = fontsize when "fn" # Font name if endtag fontnamestack.pop else fontname = param.sub(/\s+$/, "") fontnamestack.push(Font.exist?(fontname) ? fontname : "Arial") end fontname = getLastParam(fontnamestack, defaultfontname) bitmap.font.name = fontname when "ar" # Right align if endtag alignstack.pop else alignstack.push(1) end nextline = 1 if x > 0 && nextline == 0 when "al" # Left align if endtag alignstack.pop else alignstack.push(0) end nextline = 1 if x > 0 && nextline == 0 when "ac" # Center align if endtag alignstack.pop else alignstack.push(2) end nextline = 1 if x > 0 && nextline == 0 when "icon" # Icon if !endtag param = param.sub(/\s+$/, "") graphic = "Graphics/Icons/#{param}" controls[i] = nil break end when "img" # Icon if !endtag param = param.sub(/\s+$/, "") param = param.split("|") graphic = param[0] if param.length > 1 graphicX = param[1].to_i graphicY = param[2].to_i graphicWidth = param[3].to_i graphicHeight = param[4].to_i end controls[i] = nil break end when "br" # Line break if !endtag nextline += 1 end when "r" # Right align this line if !endtag x = 0 rightalign = 1 lastword = [characters.length, x] end end controls[i] = nil end end bitmap.font.bold = (boldcount > 0) bitmap.font.italic = (italiccount > 0) if graphic if !graphicWidth tempgraphic = Bitmap.new(graphic) graphicWidth = tempgraphic.width graphicHeight = tempgraphic.height tempgraphic.dispose end width = graphicWidth # +8 # No padding xStart = 0 # 4 yStart = [(lineheight / 2) - (graphicHeight / 2), 0].max graphicRect = Rect.new(graphicX, graphicY, graphicWidth, graphicHeight) else xStart = 0 yStart = 0 width = isWaitChar(textchars[position]) ? 0 : bitmap.text_size(textchars[position]).width width += 2 if width > 0 && outline2count > 0 end if rightalign == 1 && nextline == 0 alignment = 1 else alignment = getLastParam(alignstack, 0) end nextline.times do havenl = true characters.push(["\n", x, y * lineheight + yDst, 0, lineheight, false, false, false, defaultcolors[0], defaultcolors[1], false, false, "", 8, position, nil, 0]) charactersInternal.push([alignment, y, 0]) y += 1 x = 0 rightalign = 0 lastword = [characters.length, x] hadspace = false hadnonspace = false end if textchars[position] == "\n" if newlineBreaks if nextline == 0 havenl = true characters.push(["\n", x, y * lineheight + yDst, 0, lineheight, false, false, false, defaultcolors[0], defaultcolors[1], false, false, "", 8, position, nil, 0]) charactersInternal.push([alignment, y, 0]) y += 1 x = 0 end rightalign = 0 hadspace = true hadnonspace = false position += 1 next else textchars[position] = " " if !graphic width = bitmap.text_size(textchars[position]).width width += 2 if width > 0 && outline2count > 0 end end end isspace = (textchars[position][/\s/] || isWaitChar(textchars[position])) ? true : false if hadspace && !isspace # set last word to here lastword[0] = characters.length lastword[1] = x hadspace = false hadnonspace = true elsif isspace hadspace = true end texty = (lineheight * y) + yDst + yStart colors = getLastColors(colorstack, opacitystack, defaultcolors) # Push character if heightDst < 0 || texty < yDst + heightDst havenl = true if !graphic && isWaitChar(textchars[position]) extraspace = (!graphic && italiccount > 0) ? 2 + (width / 2) : 2 characters.push([ graphic || textchars[position], x + xStart, texty, width + extraspace, lineheight, graphic ? true : false, (boldcount > 0), (italiccount > 0), colors[0], colors[1], (underlinecount > 0), (strikecount > 0), fontname, fontsize, position, graphicRect, ((outlinecount > 0) ? 1 : 0) + ((outline2count > 0) ? 2 : 0) ]) charactersInternal.push([alignment, y, xStart, textchars[position], extraspace]) end x += width if !explicitBreaksOnly && x + 2 > widthDst && lastword[1] != 0 && (!hadnonspace || !hadspace) havenl = true characters.insert(lastword[0], ["\n", x, y * lineheight + yDst, 0, lineheight, false, false, false, defaultcolors[0], defaultcolors[1], false, false, "", 8, position, nil]) charactersInternal.insert(lastword[0], [alignment, y, 0]) lastword[0] += 1 y += 1 x = 0 for i in lastword[0]...characters.length characters[i][2] += lineheight charactersInternal[i][1] += 1 extraspace = (charactersInternal[i][4]) ? charactersInternal[i][4] : 0 charwidth = characters[i][3] - extraspace characters[i][1] = x + charactersInternal[i][2] x += charwidth end lastword[1] = 0 end position += 1 if !graphic end # This code looks at whether the text occupies exactly two lines when # displayed. If it does, it balances the length of each line. =begin # Count total number of lines numlines = (x==0 && y>0) ? y : y+1 if numlines==2 && realtext && !realtext[/\n/] && realtext.length>=50 # Set half to middle of text (known to contain no formatting) half = realtext.length/2 leftSearch = 0 rightSearch = 0 # Search left for a space i = half while i>=0 break if realtext[i,1][/\s/]||isWaitChar(realtext[i,1]) # found a space leftSearch += 1 i -= 1 end # Search right for a space i = half while i= 0 for j in firstspace...i characters[j] = nil charactersInternal[j] = nil end firstspace = -1 elsif characters[i][0][/[ \r\t]/] if firstspace < 0 firstspace = i end else firstspace = -1 end end if firstspace > 0 for j in firstspace...characters.length characters[j] = nil charactersInternal[j] = nil end end characters.compact! charactersInternal.compact! end # Calculate Xs based on alignment # First, find all text runs with the same alignment on the same line totalwidth = 0 widthblocks = [] lastalign = 0 lasty = 0 runstart = 0 for i in 0...characters.length c = characters[i] if i > 0 && (charactersInternal[i][0] != lastalign || charactersInternal[i][1] != lasty) # Found end of run widthblocks.push([runstart, i, lastalign, totalwidth, lasty]) runstart = i totalwidth = 0 end lastalign = charactersInternal[i][0] lasty = charactersInternal[i][1] extraspace = (charactersInternal[i][4]) ? charactersInternal[i][4] : 0 totalwidth += c[3] - extraspace end widthblocks.push([runstart, characters.length, lastalign, totalwidth, lasty]) if collapseAlignments # Calculate the total width of each line totalLineWidths = [] for block in widthblocks y = block[4] if !totalLineWidths[y] totalLineWidths[y] = 0 end if totalLineWidths[y] != 0 # padding in case more than one line has different alignments totalLineWidths[y] += 16 end totalLineWidths[y] += block[3] end # Calculate a new width for the next step widthDst = [widthDst, (totalLineWidths.compact.max || 0)].min end # Now, based on the text runs found, recalculate Xs for block in widthblocks next if block[0] >= block[1] for i in block[0]...block[1] case block[2] when 1 then characters[i][1] = xDst + (widthDst - block[3] - 4) + characters[i][1] when 2 then characters[i][1] = xDst + ((widthDst / 2) - (block[3] / 2)) + characters[i][1] else characters[i][1] = xDst + characters[i][1] end end end # Remove all characters with Y greater or equal to _yDst_+_heightDst_ characters.delete_if { |ch| ch[2] >= yDst + heightDst } if heightDst >= 0 bitmap.font = oldfont dummybitmap.dispose if dummybitmap return characters end #=============================================================================== # Draw text and images on a bitmap #=============================================================================== def getLineBrokenText(bitmap, value, width, dims) x = 0 y = 0 textheight = 0 ret = [] if dims dims[0] = 0 dims[1] = 0 end line = 0 position = 0 column = 0 return ret if !bitmap || bitmap.disposed? || width <= 0 textmsg = value.clone ret.push(["", 0, 0, 0, bitmap.text_size("X").height, 0, 0, 0, 0]) while ((c = textmsg.slice!(/\n|(\S*([ \r\t\f]?))/)) != nil) break if c == "" length = c.scan(/./m).length ccheck = c if ccheck == "\n" ret.push(["\n", x, y, 0, textheight, line, position, column, 0]) x = 0 y += (textheight == 0) ? bitmap.text_size("X").height : textheight line += 1 textheight = 0 column = 0 position += length ret.push(["", x, y, 0, textheight, line, position, column, 0]) next end words = [ccheck] for i in 0...words.length word = words[i] if word && word != "" textSize = bitmap.text_size(word) textwidth = textSize.width if x > 0 && x + textwidth >= width - 2 # Zero-length word break ret.push(["", x, y, 0, textheight, line, position, column, 0]) x = 0 column = 0 y += (textheight == 0) ? bitmap.text_size("X").height : textheight line += 1 textheight = 0 end textheight = [textheight, textSize.height].max ret.push([word, x, y, textwidth, textheight, line, position, column, length]) x += textwidth dims[0] = x if dims && dims[0] < x end end position += length column += length end dims[1] = y + textheight if dims return ret end def getLineBrokenChunks(bitmap, value, width, dims, plain = false) x = 0 y = 0 ret = [] if dims dims[0] = 0 dims[1] = 0 end re = /]+)>/ reNoMatch = /]+>/ return ret if !bitmap || bitmap.disposed? || width <= 0 textmsg = value.clone color = Font.default_color while (c = textmsg.slice!(/\n|[^ \r\t\f\n\-]*\-+|(\S*([ \r\t\f]?))/)) != nil break if c == "" ccheck = c if ccheck == "\n" x = 0 y += 32 next end textcols = [] if ccheck[/ 0 && x + textwidth > width minTextSize = bitmap.text_size(word.gsub(/\s*/, "")) if x > 0 && x + minTextSize.width > width x = 0 y += 32 end end ret.push([word, x, y, textwidth, 32, color]) x += textwidth dims[0] = x if dims && dims[0] < x end if textcols[i] color = textcols[i] end end end dims[1] = y + 32 if dims return ret end def renderLineBrokenChunks(bitmap, xDst, yDst, normtext, maxheight = 0) for i in 0...normtext.length width = normtext[i][3] textx = normtext[i][1] + xDst texty = normtext[i][2] + yDst if maxheight == 0 || normtext[i][2] < maxheight bitmap.font.color = normtext[i][5] bitmap.draw_text(textx, texty, width + 2, normtext[i][4], normtext[i][0]) end end end def renderLineBrokenChunksWithShadow(bitmap, xDst, yDst, normtext, maxheight, baseColor, shadowColor) for i in 0...normtext.length width = normtext[i][3] textx = normtext[i][1] + xDst texty = normtext[i][2] + yDst if maxheight == 0 || normtext[i][2] < maxheight height = normtext[i][4] text = normtext[i][0] bitmap.font.color = shadowColor bitmap.draw_text(textx + 2, texty, width + 2, height, text) bitmap.draw_text(textx, texty + 2, width + 2, height, text) bitmap.draw_text(textx + 2, texty + 2, width + 2, height, text) bitmap.font.color = baseColor bitmap.draw_text(textx, texty, width + 2, height, text) end end end def drawBitmapBuffer(chars) width = 1 height = 1 for ch in chars chx = ch[1] + ch[3] chy = ch[2] + ch[4] width = chx if width < chx height = chy if height < chy end buffer = Bitmap.new(width, height) drawFormattedChars(buffer, chars) return buffer end def drawSingleFormattedChar(bitmap, ch) if ch[5] # If a graphic graphic = Bitmap.new(ch[0]) graphicRect = ch[15] bitmap.blt(ch[1], ch[2], graphic, graphicRect, ch[8].alpha) graphic.dispose else bitmap.font.size = ch[13] if bitmap.font.size != ch[13] if ch[0] != "\n" && ch[0] != "\r" && ch[0] != " " && !isWaitChar(ch[0]) bitmap.font.bold = ch[6] if bitmap.font.bold != ch[6] bitmap.font.italic = ch[7] if bitmap.font.italic != ch[7] bitmap.font.name = ch[12] if bitmap.font.name != ch[12] offset = 0 if ch[9] # shadow bitmap.font.color = ch[9] if (ch[16] & 1) != 0 # outline offset = 1 bitmap.draw_text(ch[1], ch[2], ch[3] + 2, ch[4], ch[0]) bitmap.draw_text(ch[1], ch[2] + 1, ch[3] + 2, ch[4], ch[0]) bitmap.draw_text(ch[1], ch[2] + 2, ch[3] + 2, ch[4], ch[0]) bitmap.draw_text(ch[1] + 1, ch[2], ch[3] + 2, ch[4], ch[0]) bitmap.draw_text(ch[1] + 1, ch[2] + 2, ch[3] + 2, ch[4], ch[0]) bitmap.draw_text(ch[1] + 2, ch[2], ch[3] + 2, ch[4], ch[0]) bitmap.draw_text(ch[1] + 2, ch[2] + 1, ch[3] + 2, ch[4], ch[0]) bitmap.draw_text(ch[1] + 2, ch[2] + 2, ch[3] + 2, ch[4], ch[0]) elsif (ch[16] & 2) != 0 # outline 2 offset = 2 bitmap.draw_text(ch[1], ch[2], ch[3] + 4, ch[4], ch[0]) bitmap.draw_text(ch[1], ch[2] + 2, ch[3] + 4, ch[4], ch[0]) bitmap.draw_text(ch[1], ch[2] + 4, ch[3] + 4, ch[4], ch[0]) bitmap.draw_text(ch[1] + 2, ch[2], ch[3] + 4, ch[4], ch[0]) bitmap.draw_text(ch[1] + 2, ch[2] + 4, ch[3] + 4, ch[4], ch[0]) bitmap.draw_text(ch[1] + 4, ch[2], ch[3] + 4, ch[4], ch[0]) bitmap.draw_text(ch[1] + 4, ch[2] + 2, ch[3] + 4, ch[4], ch[0]) bitmap.draw_text(ch[1] + 4, ch[2] + 4, ch[3] + 4, ch[4], ch[0]) else bitmap.draw_text(ch[1] + 2, ch[2], ch[3] + 2, ch[4], ch[0]) bitmap.draw_text(ch[1], ch[2] + 2, ch[3] + 2, ch[4], ch[0]) bitmap.draw_text(ch[1] + 2, ch[2] + 2, ch[3] + 2, ch[4], ch[0]) end end bitmap.font.color = ch[8] if bitmap.font.color != ch[8] bitmap.draw_text(ch[1] + offset, ch[2] + offset, ch[3], ch[4], ch[0]) else bitmap.font.color = ch[8] if bitmap.font.color != ch[8] end if ch[10] # underline bitmap.fill_rect(ch[1], ch[2] + ch[4] - 4 - [(ch[4] - bitmap.font.size) / 2, 0].max - 2, ch[3] - 2, 2, ch[8]) end if ch[11] # strikeout bitmap.fill_rect(ch[1], ch[2] + (ch[4] / 2) - 4, ch[3] - 2, 2, ch[8]) end end end def drawFormattedChars(bitmap, chars) return if chars.length == 0 || !bitmap || bitmap.disposed? oldfont = bitmap.font.clone for ch in chars drawSingleFormattedChar(bitmap, ch) end bitmap.font = oldfont end # Unused def drawTextTable(bitmap, x, y, totalWidth, rowHeight, columnWidthPercents, table) yPos = y for i in 0...table.length row = table[i] xPos = x for j in 0...row.length cell = row[j] cellwidth = columnWidthPercents[j] * totalWidth / 100 chars = getFormattedText(bitmap, xPos, yPos, cellwidth, -1, cell, rowHeight) drawFormattedChars(bitmap, chars) xPos += cellwidth end yPos += rowHeight end end def drawTextEx(bitmap, x, y, width, numlines, text, baseColor, shadowColor) normtext = getLineBrokenChunks(bitmap, text, width, nil, true) renderLineBrokenChunksWithShadow(bitmap, x, y, normtext, numlines * 32, baseColor, shadowColor) end def drawFormattedTextEx(bitmap, x, y, width, text, baseColor = nil, shadowColor = nil, lineheight = 32) base = !baseColor ? Color.new(12 * 8, 12 * 8, 12 * 8) : baseColor.clone shadow = !shadowColor ? Color.new(26 * 8, 26 * 8, 25 * 8) : shadowColor.clone text = "" + text chars = getFormattedText(bitmap, x, y, width, -1, text, lineheight) drawFormattedChars(bitmap, chars) end # Unused def pbDrawShadow(bitmap, x, y, width, height, string) return if !bitmap || !string pbDrawShadowText(bitmap, x, y, width, height, string, nil, bitmap.font.color) end def pbDrawShadowText(bitmap, x, y, width, height, string, baseColor, shadowColor = nil, align = 0) return if !bitmap || !string width = (width < 0) ? bitmap.text_size(string).width + 1 : width height = (height < 0) ? bitmap.text_size(string).height + 1 : height y += 4 if shadowColor && shadowColor.alpha > 0 bitmap.font.color = shadowColor bitmap.draw_text(x + 2, y, width, height, string, align) bitmap.draw_text(x, y + 2, width, height, string, align) bitmap.draw_text(x + 2, y + 2, width, height, string, align) end if baseColor && baseColor.alpha > 0 bitmap.font.color = baseColor bitmap.draw_text(x, y, width, height, string, align) end end def pbDrawOutlineText(bitmap, x, y, width, height, string, baseColor, shadowColor = nil, align = 0) return if !bitmap || !string width = (width < 0) ? bitmap.text_size(string).width + 4 : width height = (height < 0) ? bitmap.text_size(string).height + 4 : height if shadowColor && shadowColor.alpha > 0 bitmap.font.color = shadowColor bitmap.draw_text(x - 2, y - 2, width, height, string, align) bitmap.draw_text(x, y - 2, width, height, string, align) bitmap.draw_text(x + 2, y - 2, width, height, string, align) bitmap.draw_text(x - 2, y, width, height, string, align) bitmap.draw_text(x + 2, y, width, height, string, align) bitmap.draw_text(x - 2, y + 2, width, height, string, align) bitmap.draw_text(x, y + 2, width, height, string, align) bitmap.draw_text(x + 2, y + 2, width, height, string, align) end if baseColor && baseColor.alpha > 0 bitmap.font.color = baseColor bitmap.draw_text(x, y, width, height, string, align) end end # Draws text on a bitmap. _textpos_ is an array of text commands. Each text # command is an array that contains the following: # 0 - Text to draw # 1 - X coordinate # 2 - Y coordinate # 3 - If true or 1, the text is right aligned. If 2, the text is centered. # Otherwise, the text is left aligned. # 4 - Base color # 5 - Shadow color # 6 - If true or 1, the text has an outline. Otherwise, the text has a shadow. def pbDrawTextPositions(bitmap, textpos) for i in textpos textsize = bitmap.text_size(i[0]) x = i[1] y = i[2] + 6 case i[3] when true, 1 # right align x -= textsize.width when 2 # centered x -= (textsize.width / 2) end if i[6] == true || i[6] == 1 # outline text pbDrawOutlineText(bitmap, x, y, textsize.width, textsize.height, i[0], i[4], i[5]) else pbDrawShadowText(bitmap, x, y, textsize.width, textsize.height, i[0], i[4], i[5]) end end end #=============================================================================== # Draw images on a bitmap #=============================================================================== def pbCopyBitmap(dstbm, srcbm, x, y, opacity = 255) rc = Rect.new(0, 0, srcbm.width, srcbm.height) dstbm.blt(x, y, srcbm, rc, opacity) end def pbDrawImagePositions(bitmap, textpos) for i in textpos srcbitmap = AnimatedBitmap.new(pbBitmapName(i[0])) x = i[1] y = i[2] srcx = i[3] || 0 srcy = i[4] || 0 width = (i[5] && i[5] >= 0) ? i[5] : srcbitmap.width height = (i[6] && i[6] >= 0) ? i[6] : srcbitmap.height srcrect = Rect.new(srcx, srcy, width, height) bitmap.blt(x, y, srcbitmap.bitmap, srcrect) srcbitmap.dispose end end