1
0
mirror of https://github.com/vcmi/vcmi.git synced 2025-02-09 13:14:02 +02:00

Merge branch 'develop' into chinese

This commit is contained in:
Ivan Savenko 2024-09-27 18:48:52 +03:00 committed by GitHub
commit 4b6f8293c2
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
43 changed files with 1400 additions and 1182 deletions

View File

@ -352,7 +352,7 @@ jobs:
run: |
find . -path ./.git -prune -o -path ./AI/FuzzyLite -prune -o -path ./test/googletest \
-o -path ./osx -prune -o -type f \
-not -name '*.png' -and -not -name '*.vcxproj*' -and -not -name '*.props' -and -not -name '*.wav' -and -not -name '*.webm' -and -not -name '*.ico' -and -not -name '*.bat' -print0 | \
-not -name '*.png' -and -not -name '*.ttf' -and -not -name '*.wav' -and -not -name '*.webm' -and -not -name '*.ico' -and -not -name '*.bat' -print0 | \
{ ! xargs -0 grep -l -z -P '\r\n'; }
- name: Validate JSON

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@ -95,10 +95,10 @@ set(vcmiclientcommon_SRCS
render/ImageLocator.cpp
renderSDL/CBitmapFont.cpp
renderSDL/CBitmapHanFont.cpp
renderSDL/CTrueTypeFont.cpp
renderSDL/CursorHardware.cpp
renderSDL/CursorSoftware.cpp
renderSDL/FontChain.cpp
renderSDL/ImageScaled.cpp
renderSDL/RenderHandler.cpp
renderSDL/SDLImage.cpp
@ -303,10 +303,10 @@ set(vcmiclientcommon_HEADERS
render/IScreenHandler.h
renderSDL/CBitmapFont.h
renderSDL/CBitmapHanFont.h
renderSDL/CTrueTypeFont.h
renderSDL/CursorHardware.h
renderSDL/CursorSoftware.h
renderSDL/FontChain.h
renderSDL/ImageScaled.h
renderSDL/RenderHandler.h
renderSDL/SDLImage.h

View File

@ -112,9 +112,10 @@ std::vector<std::string> BattleConsole::splitText(const std::string &text)
boost::split(lines, text, boost::is_any_of("\n"));
const auto & font = GH.renderHandler().loadFont(FONT_SMALL);
for(const auto & line : lines)
{
if (graphics->fonts[FONT_SMALL]->getStringWidth(text) < pos.w)
if (font->getStringWidth(text) < pos.w)
{
output.push_back(line);
}
@ -1098,7 +1099,8 @@ void StackQueue::StackBox::setUnit(const battle::Unit * unit, size_t turn, std::
if(currentTurn && !owner->embedded)
{
std::string tmp = std::to_string(*currentTurn);
int len = graphics->fonts[FONT_SMALL]->getStringWidth(tmp);
const auto & font = GH.renderHandler().loadFont(FONT_SMALL);
int len = font->getStringWidth(tmp);
roundRect->pos.w = len + 6;
round->setText(tmp);
}

View File

@ -17,7 +17,9 @@
#include "../render/Colors.h"
#include "../render/EFont.h"
#include "../render/IFont.h"
#include "../render/IRenderHandler.h"
#include "../gui/TextAlignment.h"
#include "../gui/CGuiHandler.h"
#include "../render/Graphics.h"
BattleOverlayLogVisualizer::BattleOverlayLogVisualizer(
@ -30,7 +32,8 @@ BattleOverlayLogVisualizer::BattleOverlayLogVisualizer(
void BattleOverlayLogVisualizer::drawText(BattleHex hex, int lineNumber, const std::string & text)
{
Point offset = owner.fieldController->hexPositionLocal(hex).topLeft() + Point(20, 20);
int h = graphics->fonts[EFonts::FONT_TINY]->getLineHeight();
const auto & font = GH.renderHandler().loadFont(FONT_TINY);
int h = font->getLineHeight();
offset.y += h * lineNumber;

View File

@ -318,10 +318,10 @@ void BattleStacksController::showStackAmountBox(Canvas & canvas, const CStack *
boxPosition = owner.fieldController->hexPositionLocal(frontPos).center() + Point(-8, -14);
}
Point textPosition = Point(amountBG->dimensions().x/2 + boxPosition.x, boxPosition.y + graphics->fonts[EFonts::FONT_TINY]->getLineHeight() - 6);
Point textPosition = Point(amountBG->dimensions().x/2 + boxPosition.x, boxPosition.y + amountBG->dimensions().y/2);
canvas.draw(amountBG, boxPosition);
canvas.drawText(textPosition, EFonts::FONT_TINY, Colors::WHITE, ETextAlignment::TOPCENTER, TextOperations::formatMetric(stack->getCount(), 4));
canvas.drawText(textPosition, EFonts::FONT_TINY, Colors::WHITE, ETextAlignment::CENTER, TextOperations::formatMetric(stack->getCount(), 4));
}
void BattleStacksController::showStack(Canvas & canvas, const CStack * stack)

View File

@ -192,7 +192,8 @@ void CGuiHandler::drawFPSCounter()
std::string fps = std::to_string(framerate().getFramerate())+" FPS";
graphics->fonts[FONT_SMALL]->renderTextLeft(screen, fps, Colors::WHITE, Point(8 * scaling, screen->h-22 * scaling));
const auto & font = GH.renderHandler().loadFont(FONT_SMALL);
font->renderTextLeft(screen, fps, Colors::WHITE, Point(8 * scaling, screen->h-22 * scaling));
}
bool CGuiHandler::amIGuiThread()

View File

@ -19,6 +19,7 @@
#include "../gui/Shortcut.h"
#include "../render/Graphics.h"
#include "../render/IFont.h"
#include "../render/IRenderHandler.h"
#include "../widgets/CComponent.h"
#include "../widgets/ComboBox.h"
#include "../widgets/Buttons.h"
@ -284,7 +285,7 @@ EFonts InterfaceObjectConfigurable::readFont(const JsonNode & config) const
return EFonts::FONT_CALLI;
}
logGlobal->debug("Unknown font attribute");
return EFonts::FONT_TIMES;
return EFonts::FONT_MEDIUM;
}
std::pair<std::string, std::string> InterfaceObjectConfigurable::readHintText(const JsonNode & config) const
@ -357,8 +358,9 @@ std::shared_ptr<CMultiLineLabel> InterfaceObjectConfigurable::buildMultiLineLabe
auto color = readColor(config["color"]);
auto text = readText(config["text"]);
Rect rect = readRect(config["rect"]);
const auto & fontPtr = GH.renderHandler().loadFont(font);
if(!config["adoptHeight"].isNull() && config["adoptHeight"].Bool())
rect.h = graphics->fonts[font]->getLineHeight() * 2;
rect.h = fontPtr->getLineHeight() * 2;
return std::make_shared<CMultiLineLabel>(rect, font, alignment, color, text);
}

View File

@ -256,15 +256,17 @@ void InfoCard::changeSelection()
if(!showChat)
labelGroupPlayers->disable();
const auto & font = GH.renderHandler().loadFont(FONT_SMALL);
for(const auto & p : CSH->playerNames)
{
int slotsUsed = labelGroupPlayers->currentSize();
Point labelPosition;
if(slotsUsed < 4)
labelPosition = Point(24, 285 + slotsUsed * graphics->fonts[FONT_SMALL]->getLineHeight()); // left column
labelPosition = Point(24, 285 + slotsUsed * font->getLineHeight()); // left column
else
labelPosition = Point(193, 285 + (slotsUsed - 4) * graphics->fonts[FONT_SMALL]->getLineHeight()); // right column
labelPosition = Point(193, 285 + (slotsUsed - 4) * font->getLineHeight()); // right column
labelGroupPlayers->add(labelPosition.x, labelPosition.y, p.second.name);
}
@ -358,7 +360,8 @@ CChatBox::CChatBox(const Rect & rect)
pos += rect.topLeft();
setRedrawParent(true);
const int height = static_cast<int>(graphics->fonts[FONT_SMALL]->getLineHeight());
const auto & font = GH.renderHandler().loadFont(FONT_SMALL);
const int height = font->getLineHeight();
Rect textInputArea(1, rect.h - height, rect.w - 1, height);
Rect chatHistoryArea(3, 1, rect.w - 3, rect.h - height - 1);
inputBackground = std::make_shared<TransparentFilledRectangle>(textInputArea, ColorRGBA(0,0,0,192));

View File

@ -19,6 +19,7 @@
#include "../gui/WindowHandler.h"
#include "../render/Graphics.h"
#include "../render/IFont.h"
#include "../render/IRenderHandler.h"
#include "../media/ISoundPlayer.h"
#include "../widgets/CComponent.h"
#include "../widgets/ComboBox.h"
@ -1034,12 +1035,14 @@ OptionsTab::PlayerOptionsEntry::PlayerOptionsEntry(const PlayerSettings & S, con
labelPlayerNameEdit = std::make_shared<CTextInput>(Rect(6, 3, 95, 15), EFonts::FONT_SMALL, ETextAlignment::CENTER, false);
labelPlayerNameEdit->setText(name);
}
labelWhoCanPlay = std::make_shared<CMultiLineLabel>(Rect(6, 23, 45, (int)graphics->fonts[EFonts::FONT_TINY]->getLineHeight()*2), EFonts::FONT_TINY, ETextAlignment::CENTER, Colors::WHITE, CGI->generaltexth->arraytxt[206 + whoCanPlay]);
const auto & font = GH.renderHandler().loadFont(FONT_SMALL);
labelWhoCanPlay = std::make_shared<CMultiLineLabel>(Rect(6, 23, 45, font->getLineHeight()*2), EFonts::FONT_TINY, ETextAlignment::CENTER, Colors::WHITE, CGI->generaltexth->arraytxt[206 + whoCanPlay]);
auto hasHandicap = [this](){ return s->handicap.startBonus.empty() && s->handicap.percentIncome == 100 && s->handicap.percentGrowth == 100; };
std::string labelHandicapText = hasHandicap() ? CGI->generaltexth->arraytxt[210] : MetaString::createFromTextID("vcmi.lobby.handicap").toString();
labelHandicap = std::make_shared<CMultiLineLabel>(Rect(57, 24, 47, (int)graphics->fonts[EFonts::FONT_TINY]->getLineHeight()*2), EFonts::FONT_TINY, ETextAlignment::CENTER, Colors::WHITE, labelHandicapText);
handicap = std::make_shared<LRClickableArea>(Rect(56, 24, 49, (int)graphics->fonts[EFonts::FONT_TINY]->getLineHeight()*2), [](){
labelHandicap = std::make_shared<CMultiLineLabel>(Rect(57, 24, 47, font->getLineHeight()*2), EFonts::FONT_TINY, ETextAlignment::CENTER, Colors::WHITE, labelHandicapText);
handicap = std::make_shared<LRClickableArea>(Rect(56, 24, 49, font->getLineHeight()*2), [](){
if(!CSH->isHost())
return;

View File

@ -17,8 +17,10 @@
#include "../render/Colors.h"
#include "../render/EFont.h"
#include "../render/IFont.h"
#include "../render/IRenderHandler.h"
#include "../render/Graphics.h"
#include "../gui/TextAlignment.h"
#include "../gui/CGuiHandler.h"
MapOverlayLogVisualizer::MapOverlayLogVisualizer(Canvas & target, std::shared_ptr<MapViewModel> model)
@ -78,8 +80,10 @@ void MapOverlayLogVisualizer::drawText(
if(viewPort.isInside(pStart))
{
int w = graphics->fonts[EFonts::FONT_TINY]->getStringWidth(text);
int h = graphics->fonts[EFonts::FONT_TINY]->getLineHeight();
const auto & font = GH.renderHandler().loadFont(FONT_TINY);
int w = font->getStringWidth(text);
int h = font->getLineHeight();
pStart.y += h * lineNumber;

View File

@ -188,6 +188,8 @@ void MapViewCache::render(const std::shared_ptr<IMapRendererContext> & context,
if(context->showTextOverlay())
{
const auto & font = GH.renderHandler().loadFont(FONT_TINY);
for(int y = dimensions.top(); y < dimensions.bottom(); ++y)
{
for(int x = dimensions.left(); x < dimensions.right(); ++x)
@ -204,8 +206,6 @@ void MapViewCache::render(const std::shared_ptr<IMapRendererContext> & context,
else
position.y -= targetRect.h / 4;
const auto font = graphics->fonts[EFonts::FONT_TINY];
Point dimensions(font->getStringWidth(overlay), font->getLineHeight());
Rect textRect = Rect(position - dimensions / 2, dimensions).resize(2);

View File

@ -11,6 +11,7 @@
#include "Canvas.h"
#include "../gui/CGuiHandler.h"
#include "../render/IRenderHandler.h"
#include "../render/IScreenHandler.h"
#include "../renderSDL/SDL_Extensions.h"
#include "Colors.h"
@ -169,23 +170,27 @@ void Canvas::drawBorderDashed(const Rect & target, const ColorRGBA & color)
void Canvas::drawText(const Point & position, const EFonts & font, const ColorRGBA & colorDest, ETextAlignment alignment, const std::string & text )
{
const auto & fontPtr = GH.renderHandler().loadFont(font);
switch (alignment)
{
case ETextAlignment::TOPLEFT: return graphics->fonts[font]->renderTextLeft (surface, text, colorDest, transformPos(position));
case ETextAlignment::TOPCENTER: return graphics->fonts[font]->renderTextCenter(surface, text, colorDest, transformPos(position));
case ETextAlignment::CENTER: return graphics->fonts[font]->renderTextCenter(surface, text, colorDest, transformPos(position));
case ETextAlignment::BOTTOMRIGHT: return graphics->fonts[font]->renderTextRight (surface, text, colorDest, transformPos(position));
case ETextAlignment::TOPLEFT: return fontPtr->renderTextLeft (surface, text, colorDest, transformPos(position));
case ETextAlignment::TOPCENTER: return fontPtr->renderTextCenter(surface, text, colorDest, transformPos(position));
case ETextAlignment::CENTER: return fontPtr->renderTextCenter(surface, text, colorDest, transformPos(position));
case ETextAlignment::BOTTOMRIGHT: return fontPtr->renderTextRight (surface, text, colorDest, transformPos(position));
}
}
void Canvas::drawText(const Point & position, const EFonts & font, const ColorRGBA & colorDest, ETextAlignment alignment, const std::vector<std::string> & text )
{
const auto & fontPtr = GH.renderHandler().loadFont(font);
switch (alignment)
{
case ETextAlignment::TOPLEFT: return graphics->fonts[font]->renderTextLinesLeft (surface, text, colorDest, transformPos(position));
case ETextAlignment::TOPCENTER: return graphics->fonts[font]->renderTextLinesCenter(surface, text, colorDest, transformPos(position));
case ETextAlignment::CENTER: return graphics->fonts[font]->renderTextLinesCenter(surface, text, colorDest, transformPos(position));
case ETextAlignment::BOTTOMRIGHT: return graphics->fonts[font]->renderTextLinesRight (surface, text, colorDest, transformPos(position));
case ETextAlignment::TOPLEFT: return fontPtr->renderTextLinesLeft (surface, text, colorDest, transformPos(position));
case ETextAlignment::TOPCENTER: return fontPtr->renderTextLinesCenter(surface, text, colorDest, transformPos(position));
case ETextAlignment::CENTER: return fontPtr->renderTextLinesCenter(surface, text, colorDest, transformPos(position));
case ETextAlignment::BOTTOMRIGHT: return fontPtr->renderTextLinesRight (surface, text, colorDest, transformPos(position));
}
}

View File

@ -15,7 +15,7 @@
struct SDL_Surface;
class IImage;
enum EFonts : int;
enum EFonts : int8_t;
enum class CanvasScalingPolicy
{

View File

@ -9,7 +9,15 @@
*/
#pragma once
enum EFonts : int
enum EFonts : int8_t
{
FONT_BIG, FONT_CALLI, FONT_CREDITS, FONT_HIGH_SCORE, FONT_MEDIUM, FONT_SMALL, FONT_TIMES, FONT_TINY, FONT_VERD
FONT_BIG,
FONT_CALLI,
FONT_CREDITS,
FONT_HIGH_SCORE,
FONT_MEDIUM,
FONT_SMALL,
FONT_TIMES,
FONT_TINY,
FONT_VERD
};

View File

@ -19,25 +19,15 @@
#include <vcmi/spells/Service.h>
#include "../renderSDL/SDL_Extensions.h"
#include "../renderSDL/CBitmapFont.h"
#include "../renderSDL/CBitmapHanFont.h"
#include "../renderSDL/CTrueTypeFont.h"
#include "../render/CAnimation.h"
#include "../render/IImage.h"
#include "../render/IRenderHandler.h"
#include "../gui/CGuiHandler.h"
#include "../lib/filesystem/Filesystem.h"
#include "../lib/filesystem/CBinaryReader.h"
#include "../../lib/json/JsonNode.h"
#include "../lib/modding/CModHandler.h"
#include "../lib/modding/ModScope.h"
#include "CGameInfo.h"
#include "../lib/VCMI_Lib.h"
#include "../CCallback.h"
#include "../lib/texts/CGeneralTextHandler.h"
#include "../lib/vcmi_endian.h"
#include "../lib/CStopWatch.h"
#include "../lib/CHeroHandler.h"
#include <SDL_surface.h>
@ -127,7 +117,6 @@ void Graphics::initializeBattleGraphics()
}
Graphics::Graphics()
{
loadFonts();
loadPaletteAndColors();
initializeBattleGraphics();
loadErmuToPicture();
@ -166,29 +155,6 @@ void Graphics::setPlayerFlagColor(SDL_Palette * targetPalette, PlayerColor playe
}
}
void Graphics::loadFonts()
{
const JsonNode config(JsonPath::builtin("config/fonts.json"));
const JsonVector & bmpConf = config["bitmap"].Vector();
const JsonNode & ttfConf = config["trueType"];
const JsonNode & hanConf = config["bitmapHan"];
assert(bmpConf.size() == FONTS_NUMBER);
for (size_t i=0; i<FONTS_NUMBER; i++)
{
std::string filename = bmpConf[i].String();
if (!hanConf[filename].isNull())
fonts[i] = std::make_shared<CBitmapHanFont>(hanConf[filename]);
else if (!ttfConf[filename].isNull()) // no ttf override
fonts[i] = std::make_shared<CTrueTypeFont>(ttfConf[filename]);
else
fonts[i] = std::make_shared<CBitmapFont>(filename);
}
}
void Graphics::loadErmuToPicture()
{
//loading ERMU to picture

View File

@ -9,26 +9,11 @@
*/
#pragma once
#include "../lib/GameConstants.h"
#include "../lib/constants/NumericConstants.h"
#include "../lib/constants/EntityIdentifiers.h"
#include "../lib/Color.h"
#include "../lib/filesystem/ResourcePath.h"
VCMI_LIB_NAMESPACE_BEGIN
class CGHeroInstance;
class CGTownInstance;
class CHeroClass;
struct InfoAboutHero;
struct InfoAboutTown;
class CGObjectInstance;
class ObjectTemplate;
class EntityService;
class JsonNode;
VCMI_LIB_NAMESPACE_END
struct SDL_Palette;
class IFont;
/// Handles fonts, hero images, town images, various graphics
class Graphics
@ -36,13 +21,8 @@ class Graphics
void initializeBattleGraphics();
void loadPaletteAndColors();
void loadErmuToPicture();
void loadFonts();
public:
//Fonts
static const int FONTS_NUMBER = 9;
std::array< std::shared_ptr<IFont>, FONTS_NUMBER> fonts;
using PlayerPalette = std::array<ColorRGBA, 32>;
//various graphics

View File

@ -23,13 +23,33 @@ int IFont::getScalingFactor() const
return GH.screenHandler().getScalingFactor();
}
size_t IFont::getLineHeight() const
{
return getLineHeightScaled() / getScalingFactor();
}
size_t IFont::getGlyphWidth(const char * data) const
{
return getGlyphWidthScaled(data) / getScalingFactor();
}
size_t IFont::getStringWidth(const std::string & data) const
{
return getStringWidthScaled(data) / getScalingFactor();
}
size_t IFont::getFontAscent() const
{
return getFontAscentScaled() / getScalingFactor();
}
size_t IFont::getStringWidthScaled(const std::string & data) const
{
size_t width = 0;
for(size_t i=0; i<data.size(); i += TextOperations::getUnicodeCharacterSize(data[i]))
{
width += getGlyphWidth(data.data() + i);
width += getGlyphWidthScaled(data.data() + i);
}
return width;
}

View File

@ -19,8 +19,6 @@ struct SDL_Surface;
class IFont : boost::noncopyable
{
protected:
/// Internal function to render font, see renderTextLeft
virtual void renderText(SDL_Surface * surface, const std::string & data, const ColorRGBA & color, const Point & pos) const = 0;
int getScalingFactor() const;
@ -29,11 +27,27 @@ public:
{}
/// Returns height of font
virtual size_t getLineHeight() const = 0;
virtual size_t getLineHeightScaled() const = 0;
/// Returns width, in pixels of a character glyph. Pointer must contain at least characterSize valid bytes
virtual size_t getGlyphWidth(const char * data) const = 0;
virtual size_t getGlyphWidthScaled(const char * data) const = 0;
/// Return width of the string
virtual size_t getStringWidth(const std::string & data) const;
virtual size_t getStringWidthScaled(const std::string & data) const;
/// Returns distance from top of the font glyphs to baseline
virtual size_t getFontAscentScaled() const = 0;
/// Returns height of font
size_t getLineHeight() const;
/// Returns width, in pixels of a character glyph. Pointer must contain at least characterSize valid bytes
size_t getGlyphWidth(const char * data) const;
/// Return width of the string
size_t getStringWidth(const std::string & data) const;
/// Returns distance from top of the font glyphs to baseline
size_t getFontAscent() const;
/// Internal function to render font, see renderTextLeft
virtual void renderText(SDL_Surface * surface, const std::string & data, const ColorRGBA & color, const Point & pos) const = 0;
virtual bool canRepresentCharacter(const char * data) const = 0;
/**
* @param surface - destination to print text on

View File

@ -17,9 +17,11 @@ VCMI_LIB_NAMESPACE_END
struct SDL_Surface;
class IFont;
class IImage;
class CAnimation;
enum class EImageBlitMode : uint8_t;
enum EFonts : int8_t;
class IRenderHandler : public boost::noncopyable
{
@ -40,4 +42,7 @@ public:
/// Loads animation using given path
virtual std::shared_ptr<CAnimation> loadAnimation(const AnimationPath & path, EImageBlitMode mode) = 0;
/// Returns font with specified identifer
virtual std::shared_ptr<const IFont> loadFont(EFonts font) = 0;
};

View File

@ -96,21 +96,14 @@ static AtlasLayout doAtlasPacking(const std::map<int, Point> & images)
}
}
void CBitmapFont::loadModFont(const std::string & modName, const ResourcePath & resource, std::unordered_map<CodePoint, EntryFNT> & loadedChars)
void CBitmapFont::loadFont(const ResourcePath & resource, std::unordered_map<CodePoint, EntryFNT> & loadedChars)
{
if (!CResourceHandler::get(modName)->existsResource(resource))
{
logGlobal->error("Failed to load font %s from mod %s", resource.getName(), modName);
return;
}
auto data = CResourceHandler::get(modName)->load(resource)->readAll();
std::string modLanguage = CGI->modh->getModLanguage(modName);
auto data = CResourceHandler::get()->load(resource)->readAll();
std::string modName = VLC->modh->findResourceOrigin(resource);
std::string modLanguage = VLC->modh->getModLanguage(modName);
std::string modEncoding = Languages::getLanguageOptions(modLanguage).encoding;
uint32_t dataHeight = data.first[5];
maxHeight = std::max(maxHeight, dataHeight);
height = data.first[5];
constexpr size_t symbolsInFile = 0x100;
constexpr size_t baseIndex = 32;
@ -126,10 +119,10 @@ void CBitmapFont::loadModFont(const std::string & modName, const ResourcePath &
symbol.leftOffset = read_le_u32(data.first.get() + baseIndex + charIndex * 12 + 0);
symbol.width = read_le_u32(data.first.get() + baseIndex + charIndex * 12 + 4);
symbol.rightOffset = read_le_u32(data.first.get() + baseIndex + charIndex * 12 + 8);
symbol.height = dataHeight;
symbol.height = height;
uint32_t pixelDataOffset = read_le_u32(data.first.get() + offsetIndex + charIndex * 4);
uint32_t pixelsCount = dataHeight * symbol.width;
uint32_t pixelsCount = height * symbol.width;
symbol.pixels.resize(pixelsCount);
@ -139,21 +132,27 @@ void CBitmapFont::loadModFont(const std::string & modName, const ResourcePath &
loadedChars[codepoint] = symbol;
}
// Try to use symbol 'L' to detect font 'ascent' - number of pixels above text baseline
const auto & symbolL = loadedChars['L'];
uint32_t lastNonEmptyRow = 0;
for (uint32_t row = 0; row < symbolL.height; ++row)
{
for (uint32_t col = 0; col < symbolL.width; ++col)
if (symbolL.pixels.at(row * symbolL.width + col) == 255)
lastNonEmptyRow = std::max(lastNonEmptyRow, row);
}
ascent = lastNonEmptyRow + 1;
}
CBitmapFont::CBitmapFont(const std::string & filename):
maxHeight(0)
height(0)
{
ResourcePath resource("data/" + filename, EResType::BMP_FONT);
std::unordered_map<CodePoint, EntryFNT> loadedChars;
loadModFont("core", resource, loadedChars);
for(const auto & modName : VLC->modh->getActiveMods())
{
if (CResourceHandler::get(modName)->existsResource(resource))
loadModFont(modName, resource, loadedChars);
}
loadFont(resource, loadedChars);
std::map<int, Point> atlasSymbol;
for (auto const & symbol : loadedChars)
@ -213,8 +212,6 @@ CBitmapFont::CBitmapFont(const std::string & filename):
SDL_FreeSurface(atlasImage);
atlasImage = scaledSurface;
}
IMG_SavePNG(atlasImage, ("/home/ivan/font_" + filename).c_str());
}
CBitmapFont::~CBitmapFont()
@ -222,12 +219,12 @@ CBitmapFont::~CBitmapFont()
SDL_FreeSurface(atlasImage);
}
size_t CBitmapFont::getLineHeight() const
size_t CBitmapFont::getLineHeightScaled() const
{
return maxHeight;
return height * getScalingFactor();
}
size_t CBitmapFont::getGlyphWidth(const char * data) const
size_t CBitmapFont::getGlyphWidthScaled(const char * data) const
{
CodePoint localChar = TextOperations::getUnicodeCodepoint(data, 4);
@ -236,7 +233,12 @@ size_t CBitmapFont::getGlyphWidth(const char * data) const
if (iter == chars.end())
return 0;
return iter->second.leftOffset + iter->second.positionInAtlas.w + iter->second.rightOffset;
return (iter->second.leftOffset + iter->second.positionInAtlas.w + iter->second.rightOffset) * getScalingFactor();
}
size_t CBitmapFont::getFontAscentScaled() const
{
return ascent * getScalingFactor();
}
bool CBitmapFont::canRepresentCharacter(const char *data) const

View File

@ -40,9 +40,10 @@ class CBitmapFont final : public IFont
};
std::unordered_map<CodePoint, BitmapChar> chars;
uint32_t maxHeight;
uint32_t height;
uint32_t ascent;
void loadModFont(const std::string & modName, const ResourcePath & resource, std::unordered_map<CodePoint, EntryFNT> & loadedChars);
void loadFont(const ResourcePath & resource, std::unordered_map<CodePoint, EntryFNT> & loadedChars);
void renderCharacter(SDL_Surface * surface, const BitmapChar & character, const ColorRGBA & color, int &posX, int &posY) const;
void renderText(SDL_Surface * surface, const std::string & data, const ColorRGBA & color, const Point & pos) const override;
@ -50,11 +51,12 @@ public:
explicit CBitmapFont(const std::string & filename);
~CBitmapFont();
size_t getLineHeight() const override;
size_t getGlyphWidth(const char * data) const override;
size_t getFontAscentScaled() const override;
size_t getLineHeightScaled() const override;
size_t getGlyphWidthScaled(const char * data) const override;
/// returns true if this font contains provided utf-8 character
bool canRepresentCharacter(const char * data) const;
bool canRepresentCharacter(const char * data) const override;
bool canRepresentString(const std::string & data) const;
friend class CBitmapHanFont;

View File

@ -1,127 +0,0 @@
/*
* CBitmapHanFont.cpp, part of VCMI engine
*
* Authors: listed in file AUTHORS in main folder
*
* License: GNU General Public License v2.0 or later
* Full text of license available in license.txt file, in main folder
*
*/
#include "StdInc.h"
#include "CBitmapHanFont.h"
#include "CBitmapFont.h"
#include "SDL_Extensions.h"
#include "../../lib/filesystem/Filesystem.h"
#include "../../lib/json/JsonNode.h"
#include "../../lib/Rect.h"
#include "../../lib/texts/TextOperations.h"
#include <SDL_surface.h>
size_t CBitmapHanFont::getCharacterDataOffset(size_t index) const
{
size_t rowSize = (size + 7) / 8; // 1 bit per pixel, rounded up
size_t charSize = rowSize * size; // glyph contains "size" rows
return index * charSize;
}
size_t CBitmapHanFont::getCharacterIndex(ui8 first, ui8 second) const
{
if (second > 0x7f )
second--;
return (first - 0x81) * (12*16 - 2) + (second - 0x40);
}
void CBitmapHanFont::renderCharacter(SDL_Surface * surface, int characterIndex, const ColorRGBA & color, int &posX, int &posY) const
{
//TODO: somewhat duplicated with CBitmapFont::renderCharacter();
Rect clipRect;
CSDL_Ext::getClipRect(surface, clipRect);
CSDL_Ext::TColorPutter colorPutter = CSDL_Ext::getPutterFor(surface);
uint8_t bpp = surface->format->BytesPerPixel;
// start of line, may differ from 0 due to end of surface or clipped surface
int lineBegin = std::max<int>(0, clipRect.y - posY);
int lineEnd = std::min((int)size, clipRect.y + clipRect.h - posY);
// start end end of each row, may differ from 0
int rowBegin = std::max<int>(0, clipRect.x - posX);
int rowEnd = std::min<int>((int)size, clipRect.x + clipRect.w - posX);
//for each line in symbol
for(int dy = lineBegin; dy <lineEnd; dy++)
{
uint8_t *dstLine = (uint8_t*)surface->pixels;
uint8_t *source = data.first.get() + getCharacterDataOffset(characterIndex);
// shift source\destination pixels to current position
dstLine += (posY+dy) * surface->pitch + posX * bpp;
source += ((size + 7) / 8) * dy;
//for each column in line
for(int dx = rowBegin; dx < rowEnd; dx++)
{
// select current bit in bitmap
int bit = (source[dx / 8] << (dx % 8)) & 0x80;
uint8_t* dstPixel = dstLine + dx*bpp;
if (bit != 0)
colorPutter(dstPixel, color.r, color.g, color.b);
}
}
posX += (int)size + 1;
}
void CBitmapHanFont::renderText(SDL_Surface * surface, const std::string & data, const ColorRGBA & color, const Point & pos) const
{
int posX = pos.x;
int posY = pos.y;
SDL_LockSurface(surface);
for(size_t i=0; i<data.size(); i += TextOperations::getUnicodeCharacterSize(data[i]))
{
std::string localChar = TextOperations::fromUnicode(data.substr(i, TextOperations::getUnicodeCharacterSize(data[i])), "GBK");
if (localChar.size() == 1)
fallback->renderCharacter(surface, fallback->chars[ui8(localChar[0])], color, posX, posY);
if (localChar.size() == 2)
renderCharacter(surface, (int)getCharacterIndex(localChar[0], localChar[1]), color, posX, posY);
}
SDL_UnlockSurface(surface);
}
CBitmapHanFont::CBitmapHanFont(const JsonNode &config):
fallback(new CBitmapFont(config["fallback"].String())),
data(CResourceHandler::get()->load(ResourcePath("data/" + config["name"].String(), EResType::OTHER))->readAll()),
size((size_t)config["size"].Float())
{
// basic tests to make sure that fonts are OK
// 1) fonts must contain 190 "sections", 126 symbols each.
assert(getCharacterIndex(0xfe, 0xff) == 190*126);
// 2) ensure that font size is correct - enough to fit all possible symbols
assert(getCharacterDataOffset(getCharacterIndex(0xfe, 0xff)) == data.second);
}
size_t CBitmapHanFont::getLineHeight() const
{
return std::max(size + 1, fallback->getLineHeight());
}
size_t CBitmapHanFont::getGlyphWidth(const char * data) const
{
std::string localChar = TextOperations::fromUnicode(std::string(data, TextOperations::getUnicodeCharacterSize(data[0])), "GBK");
if (localChar.size() == 1)
return fallback->getGlyphWidth(data);
if (localChar.size() == 2)
return size + 1;
return 0;
}

View File

@ -1,40 +0,0 @@
/*
* CBitmapHanFont.h, part of VCMI engine
*
* Authors: listed in file AUTHORS in main folder
*
* License: GNU General Public License v2.0 or later
* Full text of license available in license.txt file, in main folder
*
*/
#pragma once
#include "../render/IFont.h"
VCMI_LIB_NAMESPACE_BEGIN
class JsonNode;
VCMI_LIB_NAMESPACE_END
class CBitmapFont;
/// supports multi-byte characters for such languages like Chinese
class CBitmapHanFont final : public IFont
{
std::unique_ptr<CBitmapFont> fallback;
// data, directly copied from file
const std::pair<std::unique_ptr<ui8[]>, ui64> data;
// size of the font. Not available in file but needed for proper rendering
const size_t size;
size_t getCharacterDataOffset(size_t index) const;
size_t getCharacterIndex(ui8 first, ui8 second) const;
void renderCharacter(SDL_Surface * surface, int characterIndex, const ColorRGBA & color, int &posX, int &posY) const;
void renderText(SDL_Surface * surface, const std::string & data, const ColorRGBA & color, const Point & pos) const override;
public:
CBitmapHanFont(const JsonNode & config);
size_t getLineHeight() const override;
size_t getGlyphWidth(const char * data) const override;
};

View File

@ -15,6 +15,7 @@
#include "../render/Colors.h"
#include "../renderSDL/SDL_Extensions.h"
#include "../../lib/CConfigHandler.h"
#include "../../lib/json/JsonNode.h"
#include "../../lib/filesystem/Filesystem.h"
#include "../../lib/texts/TextOperations.h"
@ -29,12 +30,13 @@ std::pair<std::unique_ptr<ui8[]>, ui64> CTrueTypeFont::loadData(const JsonNode &
int CTrueTypeFont::getPointSize(const JsonNode & config) const
{
float fontScale = settings["video"]["fontScalingFactor"].Float();
int scalingFactor = getScalingFactor();
if (config.isNumber())
return config.Integer() * scalingFactor;
return std::round(config.Integer() * scalingFactor * fontScale);
else
return config[scalingFactor-1].Integer();
return std::round(config[scalingFactor-1].Integer() * fontScale);
}
TTF_Font * CTrueTypeFont::loadFont(const JsonNode &config)
@ -62,57 +64,65 @@ int CTrueTypeFont::getFontStyle(const JsonNode &config) const
CTrueTypeFont::CTrueTypeFont(const JsonNode & fontConfig):
data(loadData(fontConfig)),
font(loadFont(fontConfig), TTF_CloseFont),
dropShadow(fontConfig["blend"].Bool()),
blended(fontConfig["blend"].Bool())
dropShadow(!fontConfig["noShadow"].Bool()),
outline(fontConfig["outline"].Bool()),
blended(true)
{
assert(font);
TTF_SetFontStyle(font.get(), getFontStyle(fontConfig));
TTF_SetFontHinting(font.get(),TTF_HINTING_MONO);
std::string fallbackName = fontConfig["fallback"].String();
if (!fallbackName.empty())
fallbackFont = std::make_unique<CBitmapFont>(fallbackName);
}
CTrueTypeFont::~CTrueTypeFont() = default;
size_t CTrueTypeFont::getLineHeight() const
size_t CTrueTypeFont::getFontAscentScaled() const
{
if (fallbackFont)
return fallbackFont->getLineHeight();
return TTF_FontHeight(font.get()) / getScalingFactor();
return TTF_FontAscent(font.get());
}
size_t CTrueTypeFont::getGlyphWidth(const char *data) const
size_t CTrueTypeFont::getLineHeightScaled() const
{
if (fallbackFont && fallbackFont->canRepresentCharacter(data))
return fallbackFont->getGlyphWidth(data);
return getStringWidth(std::string(data, TextOperations::getUnicodeCharacterSize(*data)));
return TTF_FontHeight(font.get());
}
size_t CTrueTypeFont::getStringWidth(const std::string & data) const
size_t CTrueTypeFont::getGlyphWidthScaled(const char *data) const
{
if (fallbackFont && fallbackFont->canRepresentString(data))
return fallbackFont->getStringWidth(data);
return getStringWidthScaled(std::string(data, TextOperations::getUnicodeCharacterSize(*data)));
}
bool CTrueTypeFont::canRepresentCharacter(const char * data) const
{
uint32_t codepoint = TextOperations::getUnicodeCodepoint(data, TextOperations::getUnicodeCharacterSize(*data));
#if SDL_TTF_VERSION_ATLEAST(2, 0, 18)
return TTF_GlyphIsProvided32(font.get(), codepoint);
#elif SDL_TTF_VERSION_ATLEAST(2, 0, 12)
if (codepoint <= 0xffff)
return TTF_GlyphIsProvided(font.get(), codepoint);
return true;
#else
return true;
#endif
}
size_t CTrueTypeFont::getStringWidthScaled(const std::string & data) const
{
int width;
TTF_SizeUTF8(font.get(), data.c_str(), &width, nullptr);
return width / getScalingFactor();
return width;
}
void CTrueTypeFont::renderText(SDL_Surface * surface, const std::string & data, const ColorRGBA & color, const Point & pos) const
{
if (fallbackFont && fallbackFont->canRepresentString(data))
if (color.r != 0 && color.g != 0 && color.b != 0) // not black - add shadow
{
fallbackFont->renderText(surface, data, color, pos);
return;
}
if (outline)
renderText(surface, data, Colors::BLACK, pos - Point(1,1) * getScalingFactor());
if (dropShadow && color.r != 0 && color.g != 0 && color.b != 0) // not black - add shadow
renderText(surface, data, Colors::BLACK, pos + Point(1,1) * getScalingFactor());
if (dropShadow || outline)
renderText(surface, data, Colors::BLACK, pos + Point(1,1) * getScalingFactor());
}
if (!data.empty())
{

View File

@ -21,11 +21,11 @@ using TTF_Font = struct _TTF_Font;
class CTrueTypeFont final : public IFont
{
std::unique_ptr<CBitmapFont> fallbackFont;
const std::pair<std::unique_ptr<ui8[]>, ui64> data;
const std::unique_ptr<TTF_Font, void (*)(TTF_Font*)> font;
const bool blended;
const bool outline;
const bool dropShadow;
std::pair<std::unique_ptr<ui8[]>, ui64> loadData(const JsonNode & config);
@ -34,11 +34,14 @@ class CTrueTypeFont final : public IFont
int getFontStyle(const JsonNode & config) const;
void renderText(SDL_Surface * surface, const std::string & data, const ColorRGBA & color, const Point & pos) const override;
size_t getFontAscentScaled() const override;
public:
CTrueTypeFont(const JsonNode & fontConfig);
~CTrueTypeFont();
size_t getLineHeight() const override;
size_t getGlyphWidth(const char * data) const override;
size_t getStringWidth(const std::string & data) const override;
bool canRepresentCharacter(const char * data) const override;
size_t getLineHeightScaled() const override;
size_t getGlyphWidthScaled(const char * data) const override;
size_t getStringWidthScaled(const std::string & data) const override;
};

View File

@ -0,0 +1,136 @@
/*
* FontChain.cpp, part of VCMI engine
*
* Authors: listed in file AUTHORS in main folder
*
* License: GNU General Public License v2.0 or later
* Full text of license available in license.txt file, in main folder
*
*/
#include "StdInc.h"
#include "FontChain.h"
#include "CTrueTypeFont.h"
#include "CBitmapFont.h"
#include "../../lib/CConfigHandler.h"
#include "../../lib/texts/TextOperations.h"
void FontChain::renderText(SDL_Surface * surface, const std::string & data, const ColorRGBA & color, const Point & pos) const
{
auto chunks = splitTextToChunks(data);
int maxAscent = getFontAscentScaled();
Point currentPos = pos;
for (auto const & chunk : chunks)
{
Point chunkPos = currentPos;
int currAscent = chunk.font->getFontAscentScaled();
chunkPos.y += maxAscent - currAscent;
chunk.font->renderText(surface, chunk.text, color, chunkPos);
currentPos.x += chunk.font->getStringWidthScaled(chunk.text);
}
}
size_t FontChain::getFontAscentScaled() const
{
size_t maxHeight = 0;
for(const auto & font : chain)
maxHeight = std::max(maxHeight, font->getFontAscentScaled());
return maxHeight;
}
bool FontChain::bitmapFontsPrioritized() const
{
const std::string & fontType = settings["video"]["fontsType"].String();
if (fontType == "original")
return true;
if (fontType == "scalable")
return false;
// else - autoselection.
if (getScalingFactor() != 1)
return false; // If xbrz in use ttf/scalable fonts are preferred
if (!vstd::isAlmostEqual(1.0, settings["video"]["fontScalingFactor"].Float()))
return false; // If player requested non-100% scaling - use scalable fonts
return true; // else - use original bitmap fonts
}
void FontChain::addTrueTypeFont(const JsonNode & trueTypeConfig)
{
chain.insert(chain.begin(), std::make_unique<CTrueTypeFont>(trueTypeConfig));
}
void FontChain::addBitmapFont(const std::string & bitmapFilename)
{
if (bitmapFontsPrioritized())
chain.insert(chain.begin(), std::make_unique<CBitmapFont>(bitmapFilename));
else
chain.push_back(std::make_unique<CBitmapFont>(bitmapFilename));
}
bool FontChain::canRepresentCharacter(const char * data) const
{
for(const auto & font : chain)
if (font->canRepresentCharacter(data))
return true;
return false;
}
size_t FontChain::getLineHeightScaled() const
{
size_t maxHeight = 0;
for(const auto & font : chain)
maxHeight = std::max(maxHeight, font->getLineHeightScaled());
return maxHeight;
}
size_t FontChain::getGlyphWidthScaled(const char * data) const
{
for(const auto & font : chain)
if (font->canRepresentCharacter(data))
return font->getGlyphWidthScaled(data);
return 0;
}
std::vector<FontChain::TextChunk> FontChain::splitTextToChunks(const std::string & data) const
{
std::vector<TextChunk> chunks;
for (size_t i = 0; i < data.size(); i += TextOperations::getUnicodeCharacterSize(data[i]))
{
const IFont * currentFont = nullptr;
for(const auto & font : chain)
{
if (font->canRepresentCharacter(data.data() + i))
{
currentFont = font.get();
break;
}
}
if (currentFont == nullptr)
continue; // not representable
std::string symbol = data.substr(i, TextOperations::getUnicodeCharacterSize(data[i]));
if (chunks.empty() || chunks.back().font != currentFont)
chunks.push_back({currentFont, symbol});
else
chunks.back().text += symbol;
}
return chunks;
}
size_t FontChain::getStringWidthScaled(const std::string & data) const
{
size_t result = 0;
auto chunks = splitTextToChunks(data);
for (auto const & chunk : chunks)
result += chunk.font->getStringWidthScaled(chunk.text);
return result;
}

View File

@ -0,0 +1,43 @@
/*
* FontChain.h, part of VCMI engine
*
* Authors: listed in file AUTHORS in main folder
*
* License: GNU General Public License v2.0 or later
* Full text of license available in license.txt file, in main folder
*
*/
#pragma once
#include "../render/IFont.h"
VCMI_LIB_NAMESPACE_BEGIN
class JsonNode;
VCMI_LIB_NAMESPACE_END
class FontChain final : public IFont
{
struct TextChunk
{
const IFont * font;
std::string text;
};
std::vector<TextChunk> splitTextToChunks(const std::string & data) const;
std::vector<std::unique_ptr<IFont>> chain;
void renderText(SDL_Surface * surface, const std::string & data, const ColorRGBA & color, const Point & pos) const override;
size_t getFontAscentScaled() const override;
bool bitmapFontsPrioritized() const;
public:
FontChain() = default;
void addTrueTypeFont(const JsonNode & trueTypeConfig);
void addBitmapFont(const std::string & bitmapFilename);
size_t getLineHeightScaled() const override;
size_t getGlyphWidthScaled(const char * data) const override;
size_t getStringWidthScaled(const std::string & data) const override;
bool canRepresentCharacter(const char * data) const override;
};

View File

@ -12,6 +12,7 @@
#include "SDLImage.h"
#include "ImageScaled.h"
#include "FontChain.h"
#include "../gui/CGuiHandler.h"
@ -20,7 +21,6 @@
#include "../render/Colors.h"
#include "../render/ColorFilter.h"
#include "../render/IScreenHandler.h"
#include "../../lib/json/JsonUtils.h"
#include "../../lib/filesystem/Filesystem.h"
#include "../../lib/VCMIDirs.h"
@ -335,3 +335,32 @@ void RenderHandler::onLibraryLoadingFinished(const Services * services)
addImageListEntries(services->spells());
addImageListEntries(services->skills());
}
std::shared_ptr<const IFont> RenderHandler::loadFont(EFonts font)
{
if (fonts.count(font))
return fonts.at(font);
const int8_t index = static_cast<int8_t>(font);
auto configList = CResourceHandler::get()->getResourcesWithName(JsonPath::builtin("config/fonts.json"));
std::shared_ptr<FontChain> loadedFont = std::make_shared<FontChain>();
std::string bitmapPath;
for(auto & loader : configList)
{
auto stream = loader->load(JsonPath::builtin("config/fonts.json"));
std::unique_ptr<ui8[]> textData(new ui8[stream->getSize()]);
stream->read(textData.get(), stream->getSize());
const JsonNode config(reinterpret_cast<const std::byte*>(textData.get()), stream->getSize(), "config/fonts.json");
const JsonVector & bmpConf = config["bitmap"].Vector();
const JsonNode & ttfConf = config["trueType"];
bitmapPath = bmpConf[index].String();
if (!ttfConf[bitmapPath].isNull())
loadedFont->addTrueTypeFont(ttfConf[bitmapPath]);
}
loadedFont->addBitmapFont(bitmapPath);
fonts[font] = loadedFont;
return loadedFont;
}

View File

@ -26,6 +26,7 @@ class RenderHandler : public IRenderHandler
std::map<AnimationPath, std::shared_ptr<CDefFile>> animationFiles;
std::map<AnimationPath, AnimationLayoutMap> animationLayouts;
std::map<ImageLocator, std::shared_ptr<ISharedImage>> imageFiles;
std::map<EFonts, std::shared_ptr<const IFont>> fonts;
std::shared_ptr<CDefFile> getAnimationFile(const AnimationPath & path);
AnimationLayoutMap & getAnimationLayout(const AnimationPath & path);
@ -59,4 +60,7 @@ public:
std::shared_ptr<CAnimation> loadAnimation(const AnimationPath & path, EImageBlitMode mode) override;
std::shared_ptr<IImage> createImage(SDL_Surface * source) override;
/// Returns font with specified identifer
std::shared_ptr<const IFont> loadFont(EFonts font) override;
};

View File

@ -21,6 +21,7 @@
#include "../gui/Shortcut.h"
#include "../render/Canvas.h"
#include "../render/IFont.h"
#include "../render/IRenderHandler.h"
#include "../render/Graphics.h"
#include "../windows/CMessage.h"
#include "../windows/InfoWindows.h"
@ -95,9 +96,11 @@ void CComponent::init(ComponentType Type, ComponentSubType Subtype, std::optiona
max = 80;
std::vector<std::string> textLines = CMessage::breakText(getSubtitle(), std::max<int>(max, pos.w), font);
const auto & fontPtr = GH.renderHandler().loadFont(font);
const int height = static_cast<int>(fontPtr->getLineHeight());
for(auto & line : textLines)
{
int height = static_cast<int>(graphics->fonts[font]->getLineHeight());
auto label = std::make_shared<CLabel>(pos.w/2, pos.h + height/2, font, ETextAlignment::CENTER, Colors::WHITE, line);
pos.h += height;

View File

@ -17,6 +17,7 @@
#include "../gui/Shortcut.h"
#include "../render/Graphics.h"
#include "../render/IFont.h"
#include "../render/IRenderHandler.h"
#include "../../lib/texts/TextOperations.h"
@ -190,8 +191,9 @@ void CTextInput::updateLabel()
std::string visibleText = getVisibleText();
label->alignment = originalAlignment;
const auto & font = GH.renderHandler().loadFont(label->font);
while (graphics->fonts[label->font]->getStringWidth(visibleText) > pos.w)
while (font->getStringWidth(visibleText) > pos.w)
{
label->alignment = ETextAlignment::CENTERRIGHT;
visibleText = visibleText.substr(TextOperations::getUnicodeCharacterSize(visibleText[0]));

View File

@ -22,6 +22,7 @@
#include "../render/Canvas.h"
#include "../render/Graphics.h"
#include "../render/IFont.h"
#include "../render/IRenderHandler.h"
#include "../../lib/texts/TextOperations.h"
@ -56,8 +57,9 @@ CLabel::CLabel(int x, int y, EFonts Font, ETextAlignment Align, const ColorRGBA
if(alignment == ETextAlignment::TOPLEFT) // causes issues for MIDDLE
{
pos.w = (int)graphics->fonts[font]->getStringWidth(visibleText().c_str());
pos.h = (int)graphics->fonts[font]->getLineHeight();
const auto & fontPtr = GH.renderHandler().loadFont(font);
pos.w = fontPtr->getStringWidth(visibleText().c_str());
pos.h = fontPtr->getLineHeight();
}
}
@ -114,8 +116,12 @@ void CLabel::setMaxWidth(int width)
void CLabel::trimText()
{
if(maxWidth > 0)
while ((int)graphics->fonts[font]->getStringWidth(visibleText().c_str()) > maxWidth)
{
const auto & fontPtr = GH.renderHandler().loadFont(font);
while (fontPtr->getStringWidth(visibleText().c_str()) > maxWidth)
TextOperations::trimRightUnicode(text);
}
}
void CLabel::setColor(const ColorRGBA & Color)
@ -132,7 +138,8 @@ void CLabel::setColor(const ColorRGBA & Color)
size_t CLabel::getWidth()
{
return graphics->fonts[font]->getStringWidth(visibleText());
const auto & fontPtr = GH.renderHandler().loadFont(font);
return fontPtr->getStringWidth(visibleText());
}
CMultiLineLabel::CMultiLineLabel(Rect position, EFonts Font, ETextAlignment Align, const ColorRGBA & Color, const std::string & Text) :
@ -171,7 +178,7 @@ void CMultiLineLabel::setText(const std::string & Txt)
void CTextContainer::blitLine(Canvas & to, Rect destRect, std::string what)
{
const auto f = graphics->fonts[font];
const auto f = GH.renderHandler().loadFont(font);
Point where = destRect.topLeft();
const std::string delimiters = "{}";
auto delimitersCount = std::count_if(what.cbegin(), what.cend(), [&delimiters](char c)
@ -264,7 +271,7 @@ void CMultiLineLabel::showAll(Canvas & to)
{
CIntObject::showAll(to);
const auto f = graphics->fonts[font];
const auto & fontPtr = GH.renderHandler().loadFont(font);
// calculate which lines should be visible
int totalLines = static_cast<int>(lines.size());
@ -274,17 +281,17 @@ void CMultiLineLabel::showAll(Canvas & to)
if(beginLine < 0)
beginLine = 0;
else
beginLine /= (int)f->getLineHeight();
beginLine /= fontPtr->getLineHeight();
if(endLine < 0)
endLine = 0;
else
endLine /= (int)f->getLineHeight();
endLine /= fontPtr->getLineHeight();
endLine++;
// and where they should be displayed
Point lineStart = getTextLocation().topLeft() - visibleSize + Point(0, beginLine * (int)f->getLineHeight());
Point lineSize = Point(getTextLocation().w, (int)f->getLineHeight());
Point lineStart = getTextLocation().topLeft() - visibleSize + Point(0, beginLine * fontPtr->getLineHeight());
Point lineSize = Point(getTextLocation().w, fontPtr->getLineHeight());
CSDL_Ext::CClipRectGuard guard(to.getInternalSurface(), getTextLocation()); // to properly trim text that is too big to fit
@ -293,7 +300,7 @@ void CMultiLineLabel::showAll(Canvas & to)
if(!lines[i].empty()) //non-empty line
blitLine(to, Rect(lineStart, lineSize), lines[i]);
lineStart.y += (int)f->getLineHeight();
lineStart.y += fontPtr->getLineHeight();
}
}
@ -301,15 +308,15 @@ void CMultiLineLabel::splitText(const std::string & Txt, bool redrawAfter)
{
lines.clear();
const auto f = graphics->fonts[font];
int lineHeight = static_cast<int>(f->getLineHeight());
const auto & fontPtr = GH.renderHandler().loadFont(font);
int lineHeight = static_cast<int>(fontPtr->getLineHeight());
lines = CMessage::breakText(Txt, pos.w, font);
textSize.y = lineHeight * (int)lines.size();
textSize.x = 0;
for(const std::string & line : lines)
vstd::amax(textSize.x, f->getStringWidth(line.c_str()));
vstd::amax(textSize.x, fontPtr->getStringWidth(line.c_str()));
if(redrawAfter)
redraw();
}
@ -322,7 +329,8 @@ Rect CMultiLineLabel::getTextLocation()
if(pos.h <= textSize.y)
return pos;
Point textSize(pos.w, (int)graphics->fonts[font]->getLineHeight() * (int)lines.size());
const auto & fontPtr = GH.renderHandler().loadFont(font);
Point textSize(pos.w, fontPtr->getLineHeight() * (int)lines.size());
Point textOffset(pos.w - textSize.x, pos.h - textSize.y);
switch(alignment)
@ -421,11 +429,12 @@ void CTextBox::setText(const std::string & text)
label->pos.w = pos.w - 16;
assert(label->pos.w > 0);
label->setText(text);
const auto & fontPtr = GH.renderHandler().loadFont(label->font);
OBJECT_CONSTRUCTION;
slider = std::make_shared<CSlider>(Point(pos.w - 16, 0), pos.h, std::bind(&CTextBox::sliderMoved, this, _1),
label->pos.h, label->textSize.y, 0, Orientation::VERTICAL, CSlider::EStyle(sliderStyle));
slider->setScrollStep((int)graphics->fonts[label->font]->getLineHeight());
slider->setScrollStep(fontPtr->getLineHeight());
slider->setPanningStep(1);
slider->setScrollBounds(pos - slider->pos.topLeft());
}

View File

@ -70,6 +70,8 @@ std::vector<std::string> CMessage::breakText(std::string text, size_t maxLineWid
boost::algorithm::trim_right_if(text, boost::algorithm::is_any_of(std::string(" ")));
const auto & fontPtr = GH.renderHandler().loadFont(font);
// each iteration generates one output line
while(text.length())
{
@ -83,7 +85,7 @@ std::vector<std::string> CMessage::breakText(std::string text, size_t maxLineWid
std::string printableString;
// loops till line is full or end of text reached
while(currPos < text.length() && text[currPos] != 0x0a && graphics->fonts[font]->getStringWidth(printableString) <= maxLineWidth)
while(currPos < text.length() && text[currPos] != 0x0a && fontPtr->getStringWidth(printableString) <= maxLineWidth)
{
symbolSize = TextOperations::getUnicodeCharacterSize(text[currPos]);
@ -193,9 +195,9 @@ std::string CMessage::guessHeader(const std::string & msg)
int CMessage::guessHeight(const std::string & txt, int width, EFonts font)
{
const auto f = graphics->fonts[font];
const auto & fontPtr = GH.renderHandler().loadFont(font);
const auto lines = CMessage::breakText(txt, width, font);
size_t lineHeight = f->getLineHeight();
size_t lineHeight = fontPtr->getLineHeight();
return lineHeight * lines.size();
}

View File

@ -5,12 +5,12 @@
"bitmap" :
[
"BIGFONT", // Mostly used for window titles
"CALLI10R", // Unused in VCMI
"CREDITS", // Used for credits menu
"HISCORE", // Unused in VCMI
"CALLI10R", // Only in World View menu
"CREDITS", // Only in Credits menu
"HISCORE", // Only in High Scores menu
"MEDFONT", // Some titles
"SMALFONT", // Most of the messages
"TIMES08R", // Used to display amounts on creature card
"TIMES08R", // Unused in VCMI
"TINY", // Some text
"VERD10B" // Unused in VCMI
],
@ -25,17 +25,18 @@
// b) list of scaling factors for each scaling mode, e.g. [ 10, 16, 22, 26]. In this case game will select point size according to xBRZ scaling factor
// so unscaled mode will use 10px, xbrz2 will use 16px, and xbrz3 will use 22
// "style" - italic and\or bold, indicates font style
// "blend" - if set to true, font will be antialiased
// "outline" - if set, black shadow will be generated around entire text (instead of only bottom-right side)
// "noShadow" - if set, this font will not drop any shadow
"trueType":
{
//"BIGFONT" : { "file" : "LiberationSerif-Bold.ttf", "size" : 22, "blend" : true},
//"CALLI10R" : { "file" : "Georgia.ttf", "size" : 10},
//"CREDITS" : { "file" : "LiberationSerif-Bold.ttf", "size" : 28},
//"HISCORE" : { "file" : "Georgia.ttf", "size" : 13},
//"MEDFONT" : { "file" : "LiberationSerif-Bold.ttf", "size" : 16}, // breaks messages (from map events)
//"SMALFONT" : { "file" : "LiberationSerif-Regular.ttf", "size" : 13, "blend" : true},
//"TIMES08R" : { "file" : "LiberationSerif-Regular.ttf", "size" : 11, "blend" : true},
//"TINY" : { "file" : "LiberationSerif-Regular.ttf", "size" : 11, "blend" : true},
//"VERD10B" : { "file" : "Georgia.ttf", "size" : 13}
"BIGFONT" : { "file" : "NotoSerif-Bold.ttf", "size" : [ 19, 39, 58, 78] },
"CALLI10R" : { "file" : "NotoSerif-Bold.ttf", "size" : [ 12, 24, 36, 48] }, // TODO: find better matching font? This is likely non-free 'Callisto MT' font
"CREDITS" : { "file" : "NotoSerif-Black.ttf", "size" : [ 22, 44, 66, 88], "outline" : true },
"HISCORE" : { "file" : "NotoSerif-Black.ttf", "size" : [ 18, 36, 54, 72], "outline" : true },
"MEDFONT" : { "file" : "NotoSerif-Bold.ttf", "size" : [ 15, 31, 46, 62] },
"SMALFONT" : { "file" : "NotoSerif-Medium.ttf", "size" : [ 12, 24, 36, 48] },
"TIMES08R" : { "file" : "NotoSerif-Medium.ttf", "size" : [ 8, 16, 24, 32] },
"TINY" : { "file" : "NotoSans-Medium.ttf", "size" : [ 9, 19, 28, 38], "noShadow" : true }, // The only H3 font without shadow
"VERD10B" : { "file" : "NotoSans-Medium.ttf", "size" : [ 13, 26, 39, 52] }
}
}

View File

@ -166,6 +166,8 @@
"showfps",
"targetfps",
"vsync",
"fontsType",
"fontScalingFactor",
"upscalingFilter",
"fontUpscalingFilter",
"downscalingFilter"
@ -232,6 +234,15 @@
"type" : "boolean",
"default" : true
},
"fontsType" : {
"type" : "string",
"enum" : [ "auto", "original", "scalable" ],
"default" : "auto"
},
"fontScalingFactor" : {
"type" : "number",
"default" : 1
},
"fontUpscalingFilter" : {
"type" : "string",
"enum" : [ "nearest", "bilinear", "xbrz" ],

View File

@ -174,17 +174,13 @@ void CSettingsView::loadSettings()
ui->sliderControllerSticksAcceleration->setValue(settings["input"]["controllerAxisScale"].Float() * 100);
ui->lineEditGameLobbyHost->setText(QString::fromStdString(settings["lobby"]["hostname"].String()));
ui->spinBoxNetworkPortLobby->setValue(settings["lobby"]["port"].Integer());
auto mainWindow = getMainWindow();
if(mainWindow)
{
bool fontModAvailable = mainWindow->getModView()->isModInstalled("vcmi-extras.truetypefonts");
if(!fontModAvailable)
{
ui->labelTtfFont->hide();
ui->buttonTtfFont->hide();
}
}
if (settings["video"]["fontsType"].String() == "auto")
ui->buttonFontAuto->setChecked(true);
else if (settings["video"]["fontsType"].String() == "original")
ui->buttonFontOriginal->setChecked(true);
else
ui->buttonFontScalable->setChecked(true);
loadToggleButtonSettings();
}
@ -210,9 +206,9 @@ void CSettingsView::loadToggleButtonSettings()
int cursorTypeIndex = vstd::find_pos(cursorTypesList, cursorType);
setCheckbuttonState(ui->buttonCursorType, cursorTypeIndex);
auto mainWindow = getMainWindow();
if(mainWindow)
setCheckbuttonState(ui->buttonTtfFont, mainWindow->getModView()->isModEnabled("vcmi-extras.truetypefonts"));
int fontScalingPercentage = settings["video"]["fontScalingFactor"].Float() * 100;
ui->sliderScalingFont->setValue(fontScalingPercentage / 5);
}
void CSettingsView::fillValidResolutions()
@ -770,12 +766,28 @@ void CSettingsView::on_sliderControllerSticksSensitivity_valueChanged(int value)
node->Integer() = value;
}
void CSettingsView::on_buttonTtfFont_toggled(bool value)
void CSettingsView::on_sliderScalingFont_valueChanged(int value)
{
auto mainWindow = getMainWindow();
if(value)
mainWindow->getModView()->enableModByName("vcmi-extras.truetypefonts");
else
mainWindow->getModView()->disableModByName("vcmi-extras.truetypefonts");
updateCheckbuttonText(ui->buttonTtfFont);
int actualValuePercentage = value * 5;
ui->labelScalingFontValue->setText(QString("%1%").arg(actualValuePercentage));
Settings node = settings.write["video"]["fontScalingFactor"];
node->Float() = actualValuePercentage / 100.0;
}
void CSettingsView::on_buttonFontAuto_clicked(bool checked)
{
Settings node = settings.write["video"]["fontsType"];
node->String() = "auto";
}
void CSettingsView::on_buttonFontScalable_clicked(bool checked)
{
Settings node = settings.write["video"]["fontsType"];
node->String() = "scalable";
}
void CSettingsView::on_buttonFontOriginal_clicked(bool checked)
{
Settings node = settings.write["video"]["fontsType"];
node->String() = "original";
}

View File

@ -88,7 +88,13 @@ private slots:
void on_sliderControllerSticksSensitivity_valueChanged(int value);
void on_buttonTtfFont_toggled(bool value);
//void on_buttonTtfFont_toggled(bool value);
void on_sliderScalingFont_valueChanged(int value);
void on_buttonFontAuto_clicked(bool checked);
void on_buttonFontScalable_clicked(bool checked);
void on_buttonFontOriginal_clicked(bool checked);
private:
Ui::CSettingsView * ui;

File diff suppressed because it is too large Load Diff

View File

@ -102,7 +102,7 @@
<message>
<location filename="../modManager/cmodlistmodel_moc.cpp" line="44"/>
<source>Test</source>
<translation>Testa</translation>
<translation>Test</translation>
</message>
<message>
<location filename="../modManager/cmodlistmodel_moc.cpp" line="45"/>
@ -224,7 +224,7 @@
<message>
<location filename="../modManager/cmodlistview_moc.ui" line="86"/>
<source>Active</source>
<translation>Tillgångar</translation>
<translation>Aktiv</translation>
</message>
<message>
<location filename="../modManager/cmodlistview_moc.ui" line="91"/>
@ -290,7 +290,7 @@
<message>
<location filename="../modManager/cmodlistview_moc.ui" line="340"/>
<source>Abort</source>
<translation>Ge upp</translation>
<translation>Avbryt</translation>
</message>
<message>
<location filename="../modManager/cmodlistview_moc.cpp" line="289"/>
@ -315,7 +315,7 @@
<message>
<location filename="../modManager/cmodlistview_moc.cpp" line="296"/>
<source>Download size</source>
<translation>Nedladdningsstorlek</translation>
<translation>Nedladdnings-storlek</translation>
</message>
<message>
<location filename="../modManager/cmodlistview_moc.cpp" line="298"/>
@ -346,7 +346,7 @@
<message>
<location filename="../modManager/cmodlistview_moc.cpp" line="321"/>
<source>Supported VCMI version</source>
<translation>Stödd VCMI-version</translation>
<translation>VCMI-version som stöds</translation>
</message>
<message>
<location filename="../modManager/cmodlistview_moc.cpp" line="321"/>
@ -357,7 +357,7 @@
<location filename="../modManager/cmodlistview_moc.cpp" line="193"/>
<location filename="../modManager/cmodlistview_moc.cpp" line="824"/>
<source>mods repository index</source>
<translation>Modd-repositorie index</translation>
<translation>Modd-repositorie-index</translation>
</message>
<message>
<location filename="../modManager/cmodlistview_moc.cpp" line="323"/>
@ -392,22 +392,22 @@
<message>
<location filename="../modManager/cmodlistview_moc.cpp" line="359"/>
<source>This mod can not be enabled because the following mods are incompatible with it</source>
<translation>Denna modd kan inte aktiveras eftersom följande beroenden är inkompatibla med den</translation>
<translation>Denna modd kan inte aktiveras eftersom följande moddar är inkompatibla med den</translation>
</message>
<message>
<location filename="../modManager/cmodlistview_moc.cpp" line="360"/>
<source>This mod cannot be disabled because it is required by the following mods</source>
<translation>Denna modd kan inte inaktiveras eftersom den krävs för följande beroenden</translation>
<translation>Denna modd kan inte inaktiveras eftersom den krävs för följande modd</translation>
</message>
<message>
<location filename="../modManager/cmodlistview_moc.cpp" line="361"/>
<source>This mod cannot be uninstalled or updated because it is required by the following mods</source>
<translation>Denna modd kan inte avinstalleras eller uppdateras eftersom den krävs för följande beroenden</translation>
<translation>Denna modd kan inte avinstalleras eller uppdateras eftersom den krävs för följande modd</translation>
</message>
<message>
<location filename="../modManager/cmodlistview_moc.cpp" line="362"/>
<source>This is a submod and it cannot be installed or uninstalled separately from its parent mod</source>
<translation>Denna undermodd/submodd kan inte installeras eller uppdateras separat från huvud-modden</translation>
<translation>Detta är en undermodd/submodd och den kan inte installeras eller avinstalleras separat från huvud-modden</translation>
</message>
<message>
<location filename="../modManager/cmodlistview_moc.cpp" line="377"/>
@ -467,7 +467,7 @@
<message>
<location filename="../modManager/cmodlistview_moc.cpp" line="720"/>
<source>Downloading %1. %p% (%v MB out of %m MB) finished</source>
<translation>Ladda ner %1. %p% (%v MB av %m MB) slutfört</translation>
<translation>Laddar ner %1. %p% (%v MB av %m MB) slutfört</translation>
</message>
<message>
<location filename="../modManager/cmodlistview_moc.cpp" line="745"/>
@ -494,7 +494,7 @@ Fel påträffat:
Install successfully downloaded?</source>
<translation>
Installera lyckade nedladdningar?</translation>
Installation framgångsrikt nedladdad?</translation>
</message>
<message>
<location filename="../modManager/cmodlistview_moc.cpp" line="852"/>
@ -504,7 +504,7 @@ Installera lyckade nedladdningar?</translation>
<message>
<location filename="../modManager/cmodlistview_moc.cpp" line="925"/>
<source>Installing mod %1</source>
<translation>Installera mod %1</translation>
<translation>Installera modd %1</translation>
</message>
<message>
<location filename="../modManager/cmodlistview_moc.cpp" line="994"/>
@ -526,7 +526,7 @@ Installera lyckade nedladdningar?</translation>
<message>
<location filename="../modManager/cmodlistview_moc.cpp" line="1036"/>
<source>Screenshot %1</source>
<translation>Skriv ut skärm %1</translation>
<translation>Skärmbild %1</translation>
</message>
<message>
<location filename="../modManager/cmodlistview_moc.cpp" line="284"/>
@ -570,7 +570,7 @@ Installera lyckade nedladdningar?</translation>
<message>
<location filename="../modManager/cmodmanager.cpp" line="200"/>
<source>Mod is not compatible, please update VCMI and checkout latest mod revisions</source>
<translation>Modden är inte kompatibel. Vänligen uppdatera VCMI och kontrollera att du har den senaste versionen av modden</translation>
<translation>Modden är inte kompatibel. Vänligen uppdatera VCMI och kontrollera att du har den senaste kompatibla versionen av modden</translation>
</message>
<message>
<location filename="../modManager/cmodmanager.cpp" line="205"/>
@ -580,7 +580,7 @@ Installera lyckade nedladdningar?</translation>
<message>
<location filename="../modManager/cmodmanager.cpp" line="210"/>
<source>Required mod %1 is not enabled</source>
<translation>Den obligatorisk modden %1 är inte aktiverad</translation>
<translation>Den obligatoriska modden %1 är inte aktiverad</translation>
</message>
<message>
<location filename="../modManager/cmodmanager.cpp" line="219"/>
@ -616,7 +616,7 @@ Installera lyckade nedladdningar?</translation>
<message>
<location filename="../modManager/cmodmanager.cpp" line="322"/>
<source>Failed to extract mod data</source>
<translation>Det gick inte att extrahera data från modd</translation>
<translation>Misslyckades att extrahera data från modd</translation>
</message>
<message>
<location filename="../modManager/cmodmanager.cpp" line="350"/>
@ -661,7 +661,7 @@ Installera lyckade nedladdningar?</translation>
<message>
<location filename="../settingsView/csettingsview_moc.ui" line="593"/>
<source>VSync</source>
<translation>Vertikal synkronisering</translation>
<translation>Vertikal-synkronisering (VSync)</translation>
</message>
<message>
<location filename="../settingsView/csettingsview_moc.ui" line="490"/>
@ -691,7 +691,7 @@ Installera lyckade nedladdningar?</translation>
<message>
<location filename="../settingsView/csettingsview_moc.ui" line="835"/>
<source>Software Cursor</source>
<translation>Programvarumarkör (muspekare)</translation>
<translation>Programvarustyrd muspekare</translation>
</message>
<message>
<location filename="../settingsView/csettingsview_moc.ui" line="1166"/>
@ -731,7 +731,7 @@ Installera lyckade nedladdningar?</translation>
<message>
<location filename="../settingsView/csettingsview_moc.ui" line="1158"/>
<source>Upscaling Filter</source>
<translation>Förstoringsfilter</translation>
<translation>Uppskalnings-filter</translation>
</message>
<message>
<location filename="../settingsView/csettingsview_moc.ui" line="317"/>
@ -766,7 +766,7 @@ Installera lyckade nedladdningar?</translation>
<message>
<location filename="../settingsView/csettingsview_moc.ui" line="1144"/>
<source>Show Tutorial again</source>
<translation>Visa övningsgenomgången igen</translation>
<translation>Visa handledningen/övningsgenomgången igen</translation>
</message>
<message>
<location filename="../settingsView/csettingsview_moc.ui" line="1151"/>
@ -853,7 +853,7 @@ Exklusivt helskärmsläge - spelet kommer att täcka hela skärmen och använda
<message>
<location filename="../settingsView/csettingsview_moc.ui" line="407"/>
<source>Borderless fullscreen</source>
<translation>Kantlöst fönsterläge</translation>
<translation>Kantlös helskärm</translation>
</message>
<message>
<location filename="../settingsView/csettingsview_moc.ui" line="412"/>
@ -923,7 +923,7 @@ Exklusivt helskärmsläge - spelet kommer att täcka hela skärmen och använda
<message>
<location filename="../settingsView/csettingsview_moc.ui" line="646"/>
<source>Check on startup</source>
<translation>Kontrollera vid start</translation>
<translation>Kontrollera vid uppstart</translation>
</message>
<message>
<location filename="../settingsView/csettingsview_moc.ui" line="828"/>
@ -1151,12 +1151,12 @@ Exklusivt helskärmsläge - spelet kommer att täcka hela skärmen och använda
<location filename="../firstLaunch/firstlaunch_moc.ui" line="504"/>
<source>If you own Heroes III on gog.com you can download backup offline installer from gog.com, and VCMI will import Heroes III data using offline installer.
Offline installer consists of two parts, .exe and .bin. Make sure you download both of them.</source>
<translation>Om du äger Heroes III från GOG.com kan du ladda ner backup offline-installationsprogrammet från GOG.com - VCMI kommer att importera Heroes III-data med hjälp av offline-installationsprogrammet. Offline-installationsprogrammet består av två delar, en .exe och en .bin. Se till att ladda ner båda.</translation>
<translation>Om du äger Heroes III från GOG.com kan du ladda ner backup offline-installationsprogrammet från 'GOG.com'. VCMI kommer att importera Heroes III-data med hjälp av offline-installationsprogrammet. Offline-installationsprogrammet består av två delar, en '.exe'- och en '.bin'fil. Se till att ladda ner båda.</translation>
</message>
<message>
<location filename="../firstLaunch/firstlaunch_moc.ui" line="622"/>
<source>Install a translation of Heroes III in your preferred language</source>
<translation>Installera en översättning av Heroes III ditt föredragna språk</translation>
<translation>Installera en översättning av Heroes III det språk du föredrar</translation>
</message>
<message>
<location filename="../firstLaunch/firstlaunch_moc.ui" line="867"/>
@ -1166,12 +1166,12 @@ Offline installer consists of two parts, .exe and .bin. Make sure you download b
<message>
<location filename="../firstLaunch/firstlaunch_moc.ui" line="155"/>
<source>VCMI on Github</source>
<translation>VCMI Github</translation>
<translation>VCMI 'Github'</translation>
</message>
<message>
<location filename="../firstLaunch/firstlaunch_moc.ui" line="162"/>
<source>VCMI on Discord</source>
<translation>VCMI Discord</translation>
<translation>VCMI 'Discord'</translation>
</message>
<message>
<location filename="../firstLaunch/firstlaunch_moc.ui" line="178"/>
@ -1245,7 +1245,7 @@ Heroes® of Might and Magic® III HD stöds för närvarande inte!</translation>
<message>
<location filename="../firstLaunch/firstlaunch_moc.ui" line="689"/>
<source>Optionally, you can install additional mods either now, or at any point later, using the VCMI Launcher</source>
<translation>Valfritt kan du installera ytterligare moddar antingen nu eller när som helst senare med hjälp av &apos;VCMI Launcher&apos;</translation>
<translation>Du kan välja att installera ytterligare moddar, antingen nu eller vid ett senare tillfälle med hjälp av 'VCMI Launchern'</translation>
</message>
<message>
<location filename="../firstLaunch/firstlaunch_moc.ui" line="788"/>
@ -1276,7 +1276,7 @@ Heroes® of Might and Magic® III HD stöds för närvarande inte!</translation>
<location filename="../firstLaunch/firstlaunch_moc.cpp" line="313"/>
<source>Select %1 file...</source>
<comment>param is file extension</comment>
<translation>Välj filen %1...</translation>
<translation>Välj filen %1 ...</translation>
</message>
<message>
<location filename="../firstLaunch/firstlaunch_moc.cpp" line="314"/>
@ -1307,7 +1307,7 @@ Heroes® of Might and Magic® III HD stöds för närvarande inte!</translation>
<message>
<location filename="../firstLaunch/firstlaunch_moc.cpp" line="342"/>
<source>GOG installer</source>
<translation>GOG installationsprogram</translation>
<translation>GOG-Installationsprogram</translation>
</message>
<message>
<location filename="../firstLaunch/firstlaunch_moc.cpp" line="339"/>
@ -1336,7 +1336,7 @@ Heroes® of Might and Magic® III HD stöds för närvarande inte!</translation>
<location filename="../firstLaunch/firstlaunch_moc.cpp" line="445"/>
<source>Failed to detect valid Heroes III data in chosen directory.
Please select directory with installed Heroes III data.</source>
<translation>Det går inte att upptäcka giltiga Heroes III-data i den valda katalogen. Välj en mapp där Heroes III-data finns.</translation>
<translation>Misslyckades med att upptäcka giltiga Heroes III-data i den valda mappen. Vänligen välj en mapp där Heroes III-data finns installerat.</translation>
</message>
<message>
<location filename="../firstLaunch/firstlaunch_moc.cpp" line="383"/>
@ -1346,14 +1346,14 @@ Please select directory with installed Heroes III data.</source>
<message>
<location filename="../firstLaunch/firstlaunch_moc.cpp" line="399"/>
<source>Extracting error!</source>
<translation>Extraktionsfel!</translation>
<translation>Fel vid extrahering!</translation>
</message>
<message>
<location filename="../firstLaunch/firstlaunch_moc.cpp" line="469"/>
<source>Heroes III: HD Edition files are not supported by VCMI.
Please select directory with Heroes III: Complete Edition or Heroes III: Shadow of Death.</source>
<translation>Heroes III HD Edition-filer stöds inte av VCMI.
lj en mapp som innehåller data från Heroes III: Complete Edition eller Heroes III: Shadow of Death.</translation>
nligen lj en mapp som innehåller data från Heroes III: Complete Edition eller Heroes III: Shadow of Death.</translation>
</message>
<message>
<location filename="../firstLaunch/firstlaunch_moc.cpp" line="474"/>
@ -1489,7 +1489,7 @@ Orsak till fel: </translation>
<message>
<location filename="../mainwindow_moc.ui" line="20"/>
<source>VCMI Launcher</source>
<translation>VCMI Launcher</translation>
<translation>VCMI-startprogram (VCMI Launcher)</translation>
</message>
<message>
<location filename="../mainwindow_moc.ui" line="53"/>
@ -1514,7 +1514,7 @@ Orsak till fel: </translation>
<message>
<location filename="../mainwindow_moc.ui" line="259"/>
<source>Start game</source>
<translation>Starta ett spel</translation>
<translation>Starta spelet</translation>
</message>
</context>
<context>