285 lines
8.6 KiB
Ruby
285 lines
8.6 KiB
Ruby
# Copyright (c) 2018(-2023) STMicroelectronics.
|
|
# All rights reserved.
|
|
#
|
|
# This file is part of the TouchGFX 4.21.2 distribution.
|
|
#
|
|
# This software is licensed under terms that can be found in the LICENSE file in
|
|
# the root directory of this software component.
|
|
# If no LICENSE file comes with this software, it is provided AS-IS.
|
|
#
|
|
###############################################################################/
|
|
require 'json'
|
|
|
|
class LanguagesBin
|
|
def initialize(text_entries, typographies, languages, output_directory)
|
|
@text_entries = text_entries
|
|
@typographies = typographies
|
|
@languages = languages
|
|
@output_directory = output_directory
|
|
end
|
|
def run
|
|
#remove_old_binary_files
|
|
@languages.each do |language|
|
|
LanguageXxBin.new(@text_entries, @typographies, @output_directory, @languages, language).run
|
|
end
|
|
end
|
|
|
|
private
|
|
|
|
def remove_old_binary_files
|
|
# Remove any old bin file
|
|
local_path = @output_directory.gsub('\\','/')
|
|
Dir["#{local_path}/binary/Language*.bin"].each do |language_bin_file|
|
|
puts "Deleting #{language_bin_file}"
|
|
FileUtils.rm(language_bin_file)
|
|
end
|
|
end
|
|
end
|
|
|
|
class LanguageXxBin < Template
|
|
Presenter = Struct.new(:text_id, :unicodes)
|
|
LanguageHeader = Struct.new(:offset_to_texts, :offset_to_indices, :offset_to_typedtext)
|
|
TypedTextPresenter = Struct.new(:alignment, :direction, :typography)
|
|
|
|
ALIGNMENT = { "LEFT" => 0, "CENTER" => 1, "RIGHT" => 2 }
|
|
TEXT_DIRECTION = { "LTR" => 0, "RTL" => 1 }
|
|
|
|
def initialize(text_entries, typographies, output_directory, languages, language)
|
|
@languages = languages
|
|
@language = language
|
|
@typographies = typographies
|
|
@text_entries = text_entries
|
|
@output_directory = output_directory
|
|
@cache = {}
|
|
end
|
|
|
|
def cache_file
|
|
File.join(@output_directory, "cache/LanguageBin_#{@language.capitalize}.cache")
|
|
end
|
|
|
|
def alignment_to_value(alignment)
|
|
ALIGNMENT[alignment.to_s]
|
|
end
|
|
|
|
def text_direction_to_value(direction)
|
|
TEXT_DIRECTION[direction.to_s]
|
|
end
|
|
|
|
def language
|
|
@language
|
|
end
|
|
|
|
def entries
|
|
#only generate entries once
|
|
@cached_entries ||=
|
|
begin
|
|
entries = text_entries
|
|
entries = handle_no_entries(entries, "DO_NOT_USE")
|
|
present(entries)
|
|
end
|
|
end
|
|
|
|
def entries_texts_const_initialization
|
|
entries.map { |entry| " #{entry.text_id}_#{language.capitalize}" }.join(",\n")
|
|
end
|
|
|
|
def input_path
|
|
File.join(@output_directory, output_path)
|
|
end
|
|
|
|
def output_path
|
|
"binary/Language#{language.capitalize}.bin"
|
|
end
|
|
|
|
def typed_texts(language)
|
|
text_entries.collect do |entry|
|
|
typography_name = entry.typographies[language] || entry.default_typography
|
|
typography = typographies.find { |t| t.name == typography_name }
|
|
alignment = entry.alignments[language] || entry.default_alignment
|
|
direction = entry.directions[language] || entry.default_direction
|
|
TypedTextPresenter.new(alignment, direction, typography);
|
|
end
|
|
end
|
|
|
|
def typed_texts_(language)
|
|
typed_text_str = typed_texts(language)
|
|
puts "typed_text_str = #{typed_text_str}"
|
|
end
|
|
|
|
def fonts
|
|
typographies.map{ |t| Typography.new("", t.font_file, t.font_size, t.bpp) }.uniq.collect do |t|
|
|
get_getFont_name(t)
|
|
end
|
|
end
|
|
|
|
def get_font_index(typography)
|
|
fontmap[get_getFont_name(typography)]
|
|
end
|
|
|
|
def fontmap
|
|
fontmap = Hash.new
|
|
fonts.each_with_index do |f, i|
|
|
fontmap[f] = i
|
|
end
|
|
fontmap
|
|
end
|
|
|
|
def header(entries)
|
|
nb_entries = 0
|
|
header_struct_size = 12
|
|
header_unicodes_size = 0;
|
|
offset_to_texts = 0
|
|
offset_to_indices = 0
|
|
offset_to_typedtext = 0
|
|
entries.each do |entry|
|
|
nb_entries += 1
|
|
entry.unicodes.split(', ').each { |c|
|
|
header_unicodes_size += 2
|
|
}
|
|
end
|
|
offset_to_texts = header_struct_size
|
|
offset_to_indices = ((offset_to_texts + header_unicodes_size + 3) &~ 0x3)
|
|
offset_to_typedtext = ((offset_to_indices + (4 * nb_entries) + 3) &~ 0x3)
|
|
#puts "Number of Entries = #{nb_entries}"
|
|
#puts "Header size = #{header_struct_size}"
|
|
#puts "Unicodes size = #{header_unicodes_size}"
|
|
#puts "Text Offset = #{offset_to_texts}"
|
|
#puts "Indices Offset = #{offset_to_indices}"
|
|
#puts "TypedText Offset = #{offset_to_typedtext}"
|
|
LanguageHeader.new('0x' + offset_to_texts.to_s(16), '0x' + offset_to_indices.to_s(16), '0x' + offset_to_typedtext.to_s(16))
|
|
end
|
|
|
|
def output_filename
|
|
File.join(@output_directory, output_path)
|
|
end
|
|
|
|
def run
|
|
#build cache dictionary
|
|
@cache["typographies"] = typographies.collect{|t| [t.name, t.font_file, t.font_size, t.bpp] }
|
|
@cache["language"] = @language
|
|
@cache["language_index"] = @languages.index(@language)
|
|
list = [] #list of index,textid
|
|
entries.each_with_index do |entry, index|
|
|
list[index] = [entry.unicodes, entry.text_id]
|
|
end
|
|
@cache["indices"] = list
|
|
|
|
new_cache_file = false
|
|
if not File::exists?(cache_file)
|
|
new_cache_file = true
|
|
else
|
|
#cache file exists, compare data with cache file
|
|
old_cache = JSON.parse(File.read(cache_file))
|
|
new_cache_file = (old_cache != @cache)
|
|
end
|
|
|
|
if new_cache_file
|
|
#write new cache file
|
|
FileIO.write_file_silent(cache_file, @cache.to_json)
|
|
end
|
|
|
|
if !File::exists?(output_filename) || new_cache_file
|
|
#generate LanguageXX.bin
|
|
FileUtils.mkdir_p(File.dirname(input_path))
|
|
callingPath = Pathname.new($calling_path)
|
|
filePath = Pathname.new(input_path)
|
|
puts "Generating #{filePath.relative_path_from(callingPath)}"
|
|
File.open(input_path,'wb') do |f|
|
|
# create indices array
|
|
indices_arr = []
|
|
|
|
# Writing Language Header
|
|
lang_header = header(entries)
|
|
lang_header.each { |c|
|
|
f.write [c.to_i(16)].pack("L")
|
|
}
|
|
|
|
# Writing Texts data
|
|
indices_arr.clear
|
|
indices_arr << 0 # first element is @ offset zero
|
|
nb_data_in_entry = 0
|
|
entries.each do |entry|
|
|
#puts "All Unicodes #{entry.unicodes}"
|
|
entry.unicodes.split(', ').each { |c|
|
|
f.write [c.to_i(16)].pack("S")
|
|
nb_data_in_entry += 1
|
|
}
|
|
indices_arr << nb_data_in_entry #populate the indices array
|
|
end
|
|
|
|
# Add padding to align on word size for next indeces data writing
|
|
loop do
|
|
if Integer(f.pos) == Integer(lang_header.offset_to_indices)
|
|
break
|
|
end
|
|
f.write ["0x00".to_i(16)].pack("S")
|
|
end
|
|
|
|
# Remove last indice
|
|
indices_arr.pop
|
|
|
|
# Writing Indices
|
|
indices_arr.each { |idx| f.write [idx].pack("L") }
|
|
|
|
# Add padding to align on word size for next typed_text data writing
|
|
loop do
|
|
if Integer(f.pos) == Integer(lang_header.offset_to_typedtext)
|
|
break
|
|
end
|
|
f.write ["0x00".to_i(16)].pack("S")
|
|
end
|
|
|
|
# Create and Fill TypedTextsData Array
|
|
typed_text_arr = []
|
|
if typed_texts(language).empty?
|
|
#puts " { #{0}, #{alignment_to_value("LEFT")}, #{text_direction_to_value("LTR")} }"
|
|
typed_text_arr << 0 << alignment_to_value("LEFT") << text_direction_to_value("LTR")
|
|
else
|
|
typed_texts(language).map do |typed_text|
|
|
fontIdx = get_font_index(typed_text.typography)
|
|
alignment = alignment_to_value(typed_text.alignment.upcase)
|
|
direction = text_direction_to_value(typed_text.direction.upcase)
|
|
#puts "Font Index --> #{fontIdx}"
|
|
#puts "Alignment --> #{typed_text.alignment.upcase}"
|
|
#puts "Text Direction --> #{typed_text.direction.upcase}"
|
|
#puts " { #{fontIdx}, #{alignment_to_value(typed_text.alignment.upcase)}, #{text_direction_to_value(typed_text.direction.upcase)} }"
|
|
combined = direction.to_s(2).to_i(2) * 4 + alignment.to_s(2).to_i(2)
|
|
typed_text_arr << fontIdx << combined
|
|
end
|
|
end
|
|
|
|
# Writing TypedTextsData
|
|
typed_text_arr.each do |idx|
|
|
f.write [idx].pack("C")
|
|
end
|
|
|
|
# # Add padding to align the binary file size on word size
|
|
loop do
|
|
if (f.pos & 0x3) == 0
|
|
break
|
|
end
|
|
f.write ["0x00".to_i(16)].pack("C")
|
|
end
|
|
end
|
|
end
|
|
end
|
|
|
|
private
|
|
|
|
def handle_no_entries(entries, text)
|
|
if entries.empty?
|
|
empty_entry = TextEntry.new(text, "typography", "left", "ltr")
|
|
empty_entry.add_translation(language, "")
|
|
[empty_entry]
|
|
else
|
|
entries
|
|
end
|
|
end
|
|
|
|
def present(entries)
|
|
entries.map do |entry|
|
|
Presenter.new(entry.cpp_text_id, ( entry.translation_in(language).unicodes.map { |u| '0x' + u.to_s(16) } ).join(', ') )
|
|
end
|
|
end
|
|
end
|