#include <map>
#include "DocStyle.h"
#include "Util.h"
#include "IniFileReader.h"
GENERATE_ENUM_SERIALIZATION_FUNCTIONS
(
TextRole,
Last,
NormalRole,
"Normal",
"Strong",
"Emphasis",
"Strong Emphasis",
"Paragraph",
"Heading 5",
"Heading 4",
"Heading 3",
"Heading 2",
"Heading 1",
"List Item - Level 1",
"List Item - Level 2",
"List Item - Level 3",
"List Item - Level 4",
"Numbered List Item - Level 1",
"Numbered List Item - Level 2",
"Numbered List Item - Level 3",
"Numbered List Item - Level 4",
"Strike Through",
"Underline",
"Quote",
"Block Quote",
"Code",
"Link"
)
GENERATE_ENUM_SERIALIZATION_FUNCTIONS
(
TextAlignment,
TA_Last,
TA_Left,
"Left",
"Center",
"Right",
"Justified"
)
GENERATE_ENUM_SERIALIZATION_FUNCTIONS
(
BulletType,
BT_Last,
BT_None,
"None",
"Circle",
"Dot",
"Dash",
"Point",
"Number",
"NumberDot",
"NumberBracket",
"NumberSlash"
)
GENERATE_ENUM_SERIALIZATION_FUNCTIONS
(
FontStyle,
FS_Last,
FS_Normal,
"Normal",
"Italics",
"Bold",
"BoldItalics",
"StrikeThrough",
"Underline",
"Light",
"LightItalics",
"Medium",
"MediumItalics",
"FixedWidth"
)
std::string valueFromMap(std::map<std::string,std::string> a_map, std::string key, std::string a_default)
{
return (a_map.count(key)) ? a_map.at(key) : a_default;
}
TextRoleProperties TextRolePropertiesFromIniSection(const IniSection& iniSection)
{
std::map<std::string,std::string> nameValuePairs = IniSectionAsMap(iniSection);
TextRoleProperties properties;
properties.m_fontName = stringToString( valueFromMap(nameValuePairs, "FontFamily", "Arial") );
properties.m_fontStyle = stringToFontStyle( valueFromMap(nameValuePairs, "FontStyle", "Normal") );
properties.m_fontSize = stringToFloat( valueFromMap(nameValuePairs, "FontSize", "12.0") );
properties.m_foregroundColorIndex = stringToInt( valueFromMap(nameValuePairs, "ForegroundColor", "0") );
properties.m_backgroundColorIndex = stringToInt( valueFromMap(nameValuePairs, "BackgroundColor", "1") );
properties.m_textIndent = stringToFloat( valueFromMap(nameValuePairs, "TextIndent", "0.0") );
properties.m_textAlignment = stringToTextAlignment(valueFromMap(nameValuePairs, "TextAlignment", "Left") );
properties.m_bulletIndent = stringToFloat( valueFromMap(nameValuePairs, "BilletIndent", "0.0") );
properties.m_bulletType = stringToBulletType( valueFromMap(nameValuePairs, "BulletType", "None") );
properties.m_lineSpacing = stringToFloat( valueFromMap(nameValuePairs, "LineSpacing", "1.0") );
properties.m_spacing = stringToFloat( valueFromMap(nameValuePairs, "Spacing", "0.0") );
return properties;
}
IniSection TextRolePropertiesToIniSection(const TextRoleProperties& properties)
{
IniSection section;
IniSectionAddValue(section, "FontFamily", stringFromString( properties.m_fontName ));
IniSectionAddValue(section, "FontStyle", stringFromFontStyle( properties.m_fontStyle ));
IniSectionAddValue(section, "FontSize", stringFromFloat( properties.m_fontSize ));
IniSectionAddValue(section, "ForegroundColor", stringFromInt( properties.m_foregroundColorIndex ));
IniSectionAddValue(section, "BackgroundColor", stringFromInt( properties.m_backgroundColorIndex ));
IniSectionAddValue(section, "TextIndent", stringFromFloat( properties.m_textIndent ));
IniSectionAddValue(section, "TextAlignment", stringFromTextAlignment(properties.m_textAlignment ));
IniSectionAddValue(section, "BilletIndent", stringFromFloat( properties.m_bulletIndent ));
IniSectionAddValue(section, "BulletType", stringFromBulletType( properties.m_bulletType ));
IniSectionAddValue(section, "LineSpacing", stringFromFloat( properties.m_lineSpacing ));
IniSectionAddValue(section, "Spacing", stringFromFloat( properties.m_spacing ));
return section;
}
TextRoleProperties DefaultTextRoleProperties()
{
TextRoleProperties defaultProps;
defaultProps.m_fontName = "Arial";
defaultProps.m_fontStyle = FS_Normal;
defaultProps.m_fontSize = 12.0;
defaultProps.m_foregroundColorIndex = 0;
defaultProps.m_backgroundColorIndex = 1;
defaultProps.m_textIndent = 0.0;
defaultProps.m_textAlignment = TA_Left;
defaultProps.m_bulletIndent = 0.0;
defaultProps.m_bulletType = BT_None;
defaultProps.m_lineSpacing = 1.0;
defaultProps.m_spacing = 0.0;
return defaultProps;
}
bool ReadRole(std::map<TextRole, TextRoleProperties>& m_rolePropertiesMap,
const std::map<std::string,IniSection>& iniMap,
TextRole role,
std::string roleStr,
const TextRoleProperties& defaults)
{
bool roleInMap = iniMap.count(roleStr);
m_rolePropertiesMap[role] = (roleInMap) ? TextRolePropertiesFromIniSection(iniMap.at(roleStr)) : defaults;
m_rolePropertiesMap[role].m_displayName = stringFromTextRole(role);
return roleInMap;
}
bool WriteRole(const std::map<TextRole, TextRoleProperties>& m_rolePropertiesMap,
std::map<std::string,IniSection>& iniMap,
TextRole role,
std::string roleStr,
const TextRoleProperties& defaults)
{
bool roleInMap = m_rolePropertiesMap.count(role);
iniMap[roleStr] = TextRolePropertiesToIniSection((roleInMap) ? m_rolePropertiesMap.at(role) : defaults);
return roleInMap;
}
struct DocStyle::Pimpl
{
std::string m_name;
// Palette info
std::map<std::string, uint32_t> m_paletteEntries;
std::string m_selectedPalette;
// Text info
TextRoleProperties m_defaults;
std::map<TextRole, TextRoleProperties> m_rolePropertiesMap;
//fontStyles[currentStyle], fontSizes[currentHeadingLevel[stackDepth]]
//HPDF_Font* fontStyles[4];
};
DocStyle::DocStyle() : m_pimpl(std::make_unique<Pimpl>())
{
}
DocStyle::~DocStyle()
{
}
std::string DocStyle::name()
{
return m_pimpl->m_name;
}
void DocStyle::setName(const std::string& name)
{
m_pimpl->m_name = name;
}
void DocStyle::readStyleFile(const char* a_fileName)
{
IniFile iniFile = IniFileReader(a_fileName);
std::map<std::string,IniSection> iniFileMap = IniFileAsMap(iniFile);
TextRoleProperties defaults = DefaultTextRoleProperties();
std::map<std::string,std::string> styleSectionMap = IniSectionAsMap(iniFileMap["Style"]);
m_pimpl->m_name = valueFromMap(styleSectionMap, "Name", "Untitled");
m_pimpl->m_selectedPalette = valueFromMap(styleSectionMap, "Palette", "");
IniSection palettesSection = iniFileMap["Palettes"];
for (auto val : palettesSection.values)
{
int col = stringToInt(val.value);
m_pimpl->m_paletteEntries.emplace(val.name, *((uint32_t*)&col));
}
// TODO: switch to using the enum serialization stuff to iterate the roles
if (ReadRole(m_pimpl->m_rolePropertiesMap, iniFileMap, NormalRole , "Normal", defaults))
defaults = m_pimpl->m_rolePropertiesMap[NormalRole]; // Make normal the defaults if it was specified
ReadRole(m_pimpl->m_rolePropertiesMap, iniFileMap, StrongRole , "Strong", defaults);
ReadRole(m_pimpl->m_rolePropertiesMap, iniFileMap, EmphasisRole , "Emphasis", defaults);
ReadRole(m_pimpl->m_rolePropertiesMap, iniFileMap, StrongEmphasisRole , "StrongEmphasis" , defaults);
ReadRole(m_pimpl->m_rolePropertiesMap, iniFileMap, ParagraphRole , "Paragraph", defaults);
ReadRole(m_pimpl->m_rolePropertiesMap, iniFileMap, Heading5Role , "Heading5", defaults);
ReadRole(m_pimpl->m_rolePropertiesMap, iniFileMap, Heading4Role , "Heading4", defaults);
ReadRole(m_pimpl->m_rolePropertiesMap, iniFileMap, Heading3Role , "Heading3", defaults);
ReadRole(m_pimpl->m_rolePropertiesMap, iniFileMap, Heading2Role , "Heading2", defaults);
ReadRole(m_pimpl->m_rolePropertiesMap, iniFileMap, Heading1Role , "Heading1", defaults);
ReadRole(m_pimpl->m_rolePropertiesMap, iniFileMap, ListItemLevel1Role , "ListItemLevel1", defaults);
ReadRole(m_pimpl->m_rolePropertiesMap, iniFileMap, ListItemLevel2Role , "ListItemLevel2", defaults);
ReadRole(m_pimpl->m_rolePropertiesMap, iniFileMap, ListItemLevel3Role , "ListItemLevel3", defaults);
ReadRole(m_pimpl->m_rolePropertiesMap, iniFileMap, ListItemLevel4Role , "ListItemLevel4", defaults);
ReadRole(m_pimpl->m_rolePropertiesMap, iniFileMap, NumberedListItemLevel1Role, "NumberedListItemLevel1", defaults);
ReadRole(m_pimpl->m_rolePropertiesMap, iniFileMap, NumberedListItemLevel2Role, "NumberedListItemLevel2", defaults);
ReadRole(m_pimpl->m_rolePropertiesMap, iniFileMap, NumberedListItemLevel3Role, "NumberedListItemLevel3", defaults);
ReadRole(m_pimpl->m_rolePropertiesMap, iniFileMap, NumberedListItemLevel4Role, "NumberedListItemLevel4", defaults);
ReadRole(m_pimpl->m_rolePropertiesMap, iniFileMap, StrikethroughRole , "Strikethrough" , defaults);
ReadRole(m_pimpl->m_rolePropertiesMap, iniFileMap, UnderlineRole , "Underline" , defaults);
ReadRole(m_pimpl->m_rolePropertiesMap, iniFileMap, QuoteRole , "Quote", defaults);
ReadRole(m_pimpl->m_rolePropertiesMap, iniFileMap, BlockQuoteRole , "BlockQuote", defaults);
ReadRole(m_pimpl->m_rolePropertiesMap, iniFileMap, CodeRole , "Code", defaults);
ReadRole(m_pimpl->m_rolePropertiesMap, iniFileMap, LinkRole , "Link", defaults);
}
void DocStyle::writeStyleFile(const char* a_fileName)
{
TextRoleProperties defaults = DefaultTextRoleProperties();
std::map<std::string,IniSection> iniFileMap;
IniSection styleSection;
styleSection.name = "Style";
IniSectionAddValue(styleSection, "Name", m_pimpl->m_name);
IniSectionAddValue(styleSection, "Palette", m_pimpl->m_selectedPalette);
iniFileMap.emplace("Style", styleSection);
IniSection palettesSection;
palettesSection.name = "Palettes";
for (auto val : m_pimpl->m_paletteEntries)
{
IniSectionAddValue(palettesSection, val.first, stringFromInt(*((int*)&val.second)));
}
iniFileMap.emplace("Palettes", palettesSection);
WriteRole(m_pimpl->m_rolePropertiesMap, iniFileMap, NormalRole , "Normal", defaults);
WriteRole(m_pimpl->m_rolePropertiesMap, iniFileMap, StrongRole , "Strong", defaults);
WriteRole(m_pimpl->m_rolePropertiesMap, iniFileMap, EmphasisRole , "Emphasis", defaults);
WriteRole(m_pimpl->m_rolePropertiesMap, iniFileMap, StrongEmphasisRole , "StrongEmphasis" , defaults);
WriteRole(m_pimpl->m_rolePropertiesMap, iniFileMap, ParagraphRole , "Paragraph", defaults);
WriteRole(m_pimpl->m_rolePropertiesMap, iniFileMap, Heading5Role , "Heading5", defaults);
WriteRole(m_pimpl->m_rolePropertiesMap, iniFileMap, Heading4Role , "Heading4", defaults);
WriteRole(m_pimpl->m_rolePropertiesMap, iniFileMap, Heading3Role , "Heading3", defaults);
WriteRole(m_pimpl->m_rolePropertiesMap, iniFileMap, Heading2Role , "Heading2", defaults);
WriteRole(m_pimpl->m_rolePropertiesMap, iniFileMap, Heading1Role , "Heading1", defaults);
WriteRole(m_pimpl->m_rolePropertiesMap, iniFileMap, ListItemLevel1Role , "ListItemLevel1", defaults);
WriteRole(m_pimpl->m_rolePropertiesMap, iniFileMap, ListItemLevel2Role , "ListItemLevel2", defaults);
WriteRole(m_pimpl->m_rolePropertiesMap, iniFileMap, ListItemLevel3Role , "ListItemLevel3", defaults);
WriteRole(m_pimpl->m_rolePropertiesMap, iniFileMap, ListItemLevel4Role , "ListItemLevel4", defaults);
WriteRole(m_pimpl->m_rolePropertiesMap, iniFileMap, NumberedListItemLevel1Role, "NumberedListItemLevel1", defaults);
WriteRole(m_pimpl->m_rolePropertiesMap, iniFileMap, NumberedListItemLevel2Role, "NumberedListItemLevel2", defaults);
WriteRole(m_pimpl->m_rolePropertiesMap, iniFileMap, NumberedListItemLevel3Role, "NumberedListItemLevel3", defaults);
WriteRole(m_pimpl->m_rolePropertiesMap, iniFileMap, NumberedListItemLevel4Role, "NumberedListItemLevel4", defaults);
WriteRole(m_pimpl->m_rolePropertiesMap, iniFileMap, StrikethroughRole , "Strikethrough" , defaults);
WriteRole(m_pimpl->m_rolePropertiesMap, iniFileMap, UnderlineRole , "Underline" , defaults);
WriteRole(m_pimpl->m_rolePropertiesMap, iniFileMap, QuoteRole , "Quote", defaults);
WriteRole(m_pimpl->m_rolePropertiesMap, iniFileMap, BlockQuoteRole , "BlockQuote", defaults);
WriteRole(m_pimpl->m_rolePropertiesMap, iniFileMap, CodeRole , "Code", defaults);
WriteRole(m_pimpl->m_rolePropertiesMap, iniFileMap, LinkRole , "Link", defaults);
if (!IniFileWriter(a_fileName, IniFileFromMap(iniFileMap)))
{
printf("error while trying to save style to %s\n", a_fileName);
}
}
std::vector<std::string> DocStyle::paletteList()
{
return map2keys(m_pimpl->m_paletteEntries);
}
std::string DocStyle::selectedPalette()
{
return m_pimpl->m_selectedPalette;
}
uint32_t DocStyle::palette(const std::string& a_palette)
{
return m_pimpl->m_paletteEntries[a_palette];
}
void DocStyle::selectPalette(const std::string& a_palette)
{
m_pimpl->m_selectedPalette = a_palette;
}
void DocStyle::addPalette(const std::string& a_palette, uint32_t value)
{
m_pimpl->m_paletteEntries.emplace(a_palette, value);
}
void DocStyle::editPalette(const std::string& a_palette, uint32_t value)
{
m_pimpl->m_paletteEntries[a_palette] = value;
}
void DocStyle::removePalette(const std::string& a_palette)
{
m_pimpl->m_paletteEntries.erase(a_palette);
if (m_pimpl->m_selectedPalette == a_palette)
{
m_pimpl->m_selectedPalette = (m_pimpl->m_paletteEntries.size()) ? m_pimpl->m_paletteEntries.begin()->first : "";
}
}
TextRoleProperties DocStyle::textProperties(TextRole a_role)
{
bool inMap = m_pimpl->m_rolePropertiesMap.count(a_role);
TextRoleProperties props = (inMap) ? m_pimpl->m_rolePropertiesMap.at(a_role) : DefaultTextRoleProperties();
props.m_displayName = stringFromTextRole(a_role);
return props;
}
void DocStyle::setTextProperties(TextRole a_role, TextRoleProperties a_properties)
{
m_pimpl->m_rolePropertiesMap[a_role] = a_properties;
}
void DocStyle::font(TextRole a_role, std::string& a_fontName, float& a_fontSize)
{
TextRoleProperties props = m_pimpl->m_defaults;
if (m_pimpl->m_rolePropertiesMap.find(a_role) != m_pimpl->m_rolePropertiesMap.end())
props = m_pimpl->m_rolePropertiesMap[a_role];
a_fontName = props.m_fontName;
a_fontSize = props.m_fontSize;
}
void DocStyle::foregroundColor(TextRole a_role, float& a_red, float& a_green, float& a_blue, float& a_alpha)
{
TextRoleProperties props = m_pimpl->m_defaults;
if (m_pimpl->m_rolePropertiesMap.find(a_role) != m_pimpl->m_rolePropertiesMap.end())
props = m_pimpl->m_rolePropertiesMap[a_role];
a_red = props.m_foregoundColor[0];
a_green = props.m_foregoundColor[1];
a_blue = props.m_foregoundColor[2];
a_alpha = props.m_foregoundColor[3];
}
void DocStyle::backgroundColor(TextRole a_role, float& a_red, float& a_green, float& a_blue, float& a_alpha)
{
TextRoleProperties props = m_pimpl->m_defaults;
if (m_pimpl->m_rolePropertiesMap.find(a_role) != m_pimpl->m_rolePropertiesMap.end())
props = m_pimpl->m_rolePropertiesMap[a_role];
a_red = props.m_backgoundColor[0];
a_green = props.m_backgoundColor[1];
a_blue = props.m_backgoundColor[2];
a_alpha = props.m_backgoundColor[3];
}
void DocStyle::adornNewPage(DocOutputPage& page)
{
// Any background things can be drawn here
}
void DocStyle::adornOldPage(DocOutputPage& page)
{
page.setFontType(FT_Normal);
page.setFontSize(12.0f);
const char* text = "PDF created using WickedDocs";
float width = page.textWidth(text);
page.setAlpha(0.5);
page.setFillColor(0x0);
page.drawText((page.width() - width) * 0.5f - 0.8, page.height() - 12.0f + 0.8, text);
page.setFillColor(0xffffff);
page.drawText((page.width() - width) * 0.5f + 0.8, page.height() - 12.0f - 0.8, text);
page.setAlpha(1.0);
page.setFillColor(0x338496);
page.drawText((page.width() - width) * 0.5f, page.height() - 12.0f, text);
}