Make font editor more convenient

This commit is contained in:
mniip 2020-03-10 00:47:01 +03:00
parent dd93bbdeb3
commit 6607b7e845
4 changed files with 88 additions and 18 deletions

View File

@ -873,7 +873,7 @@ int main(int argc, char * argv[])
#else // FONTEDITOR
if(argc <= 1)
throw std::runtime_error("Not enough arguments");
throw std::runtime_error("Usage: " + ByteString(argv[0]) + " ./data/font.cpp");
engine->ShowWindow(new FontEditor(argv[1]));
#endif

View File

@ -13,6 +13,7 @@
#include "gui/interface/Button.h"
#include "gui/interface/Mouse.h"
#include "gui/interface/Keys.h"
#include "gui/interface/ScrollPanel.h"
#include "graphics/Graphics.h"
#ifdef FONTEDITOR
@ -254,6 +255,26 @@ void FontEditor::PackData(
fontRanges.push_back({0, 0});
}
class StretchLabel: public ui::Label
{
using Label::Label;
public:
int WrappedLines() const
{
return displayTextWrapper.WrappedLines();
}
};
class StretchTextbox: public ui::Textbox
{
using Textbox::Textbox;
public:
int WrappedLines() const
{
return displayTextWrapper.WrappedLines();
}
};
#define FONT_SCALE 16
FontEditor::FontEditor(ByteString _header):
ui::Window(ui::Point(0, 0), ui::Point(WINDOWW, WINDOWH)),
@ -339,8 +360,8 @@ FontEditor::FontEditor(ByteString _header):
currentX += 33;
showRulers->SetTogglable(true);
showRulers->SetToggleState(rulers);
showRulers->SetActionCallback({ [this, showGrid] {
rulers = showGrid->GetToggleState();
showRulers->SetActionCallback({ [this, showRulers] {
rulers = showRulers->GetToggleState();
} });
AddComponent(showRulers);
@ -375,29 +396,41 @@ FontEditor::FontEditor(ByteString _header):
baseline += 18;
outputPreview = new ui::Label(ui::Point(0, baseline + (Size.Y - baseline) * 3 / 5), ui::Point(Size.X, (Size.Y - baseline) * 2 / 5), "");
ui::ScrollPanel *outputPanel = new ui::ScrollPanel(ui::Point(Size.X / 2, baseline), ui::Point(Size.X / 2, Size.Y - baseline));
AddComponent(outputPanel);
StretchLabel *outputPreview = new StretchLabel(ui::Point(0, 0), ui::Point(Size.X / 2, 0), "");
outputPreview->SetMultiline(true);
outputPreview->Appearance.HorizontalAlign = ui::Appearance::AlignLeft;
outputPreview->Appearance.VerticalAlign = ui::Appearance::AlignTop;
AddComponent(outputPreview);
outputPanel->AddChild(outputPreview);
ui::Textbox *inputPreview = new ui::Textbox(ui::Point(0, baseline), ui::Point(Size.X, (Size.Y - baseline) * 3 / 5));
ui::ScrollPanel *inputPanel = new ui::ScrollPanel(ui::Point(0, baseline), ui::Point(Size.X / 2, Size.Y - baseline));
AddComponent(inputPanel);
StretchTextbox *inputPreview = new StretchTextbox(ui::Point(0, 0), ui::Point(Size.X / 2, 0));
inputPreview->SetMultiline(true);
inputPreview->SetInputType(ui::Textbox::Multiline);
inputPreview->Appearance.HorizontalAlign = ui::Appearance::AlignLeft;
inputPreview->Appearance.VerticalAlign = ui::Appearance::AlignTop;
auto textChangedCallback = [this, inputPreview] {
auto textChangedCallback = [outputPreview, outputPanel, inputPreview, inputPanel] {
String str = inputPreview->GetText();
size_t at = 0;
StringBuilder text;
while(at < str.size())
{
unsigned int ch;
unsigned int ch1, ch2;
if(str[at] != ' ')
if(String::Split split = str.SplitNumber(ch, Format::Hex(), at))
if(String::Split split1 = str.SplitNumber(ch1, Format::Hex(), at))
{
text << String::value_type(ch);
at = split.PositionAfter();
if(str[split1.PositionAfter()] == ':')
if(String::Split split2 = str.SplitNumber(ch2, Format::Hex(), split1.PositionAfter() + 1))
{
for(unsigned int ch = ch1; ch <= ch2; ch++)
text << String::value_type(ch);
at = split2.PositionAfter();
continue;
}
text << String::value_type(ch1);
at = split1.PositionAfter();
}
else
{
@ -407,16 +440,21 @@ FontEditor::FontEditor(ByteString _header):
at++;
}
outputPreview->SetText(text.Build());
outputPanel->InnerSize.Y = outputPreview->Size.Y = std::max(outputPreview->WrappedLines(), 1) * FONT_H + 2;
inputPanel->InnerSize.Y = inputPreview->Size.Y = std::max(inputPreview->WrappedLines(), 1) * FONT_H + 2;
};
inputPreview->SetActionCallback({ textChangedCallback });
inputPanel->AddChild(inputPreview);
StringBuilder input;
input << Format::Hex() << Format::Width(2);
for(unsigned int ch = 0x20; ch <= 0xFF; ch++)
for(unsigned int ch = 0x20; ch <= 0xFF; ch += 0x10)
{
if(!(ch & 0x3F))
input << 0x20 << " ";
input << ch << " ";
if(ch == 0x80)
input << "\n";
else if(ch != 0x20)
input << " 0a ";
input << ch << ":" << (ch + 0x0F);
}
inputPreview->SetText(input.Build());
textChangedCallback();
@ -478,16 +516,43 @@ void FontEditor::OnMouseDown(int x, int y, unsigned button)
}
}
void FontEditor::Translate(std::array<std::array<char, MAX_WIDTH>, FONT_H> &pixels, int dx, int dy)
{
std::array<std::array<char, MAX_WIDTH>, FONT_H> old = pixels;
for(int j = 0; j < FONT_H; j++)
for(int i = 0; i < MAX_WIDTH; i++)
if(i - dx >= 0 && i - dx + 1 < MAX_WIDTH && j - dy >= 0 && j - dy + 1 < FONT_H)
pixels[j][i] = old[j - dy][i - dx];
else
pixels[j][i] = 0;
}
void FontEditor::OnKeyPress(int key, int scan, bool repeat, bool shift, bool ctrl, bool alt)
{
if (IsFocused(NULL))
{
switch(scan)
{
case SDL_SCANCODE_UP:
if(shift)
Translate(fontPixels[currentChar], 0, -1);
break;
case SDL_SCANCODE_DOWN:
if(shift)
Translate(fontPixels[currentChar], 0, 1);
break;
case SDL_SCANCODE_LEFT:
PrevChar(); break;
if(shift)
Translate(fontPixels[currentChar], -1, 0);
else
PrevChar();
break;
case SDL_SCANCODE_RIGHT:
PrevChar(); break;
if(shift)
Translate(fontPixels[currentChar], 1, 0);
else
NextChar();
break;
case SDL_SCANCODE_ESCAPE:
case SDL_SCANCODE_Q:
if(savedButton->GetToggleState())

View File

@ -50,7 +50,6 @@ private:
ui::Textbox *currentCharTextbox;
ui::Button *savedButton;
ui::Label *outputPreview;
String::value_type currentChar;
int fgR, fgG, fgB;
@ -69,6 +68,7 @@ private:
void GrowChar();
void Render();
void Save();
void Translate(std::array<std::array<char, MAX_WIDTH>, FONT_H> &, int dx, int dy);
public:
FontEditor(ByteString header);

View File

@ -41,6 +41,11 @@ namespace ui
return wrapped_text;
}
int WrappedLines() const
{
return wrapped_lines;
}
Index IndexBegin() const
{
return Index{ 0, 0, 0 };