mirror of
https://github.com/The-Powder-Toy/The-Powder-Toy.git
synced 2025-08-29 10:49:53 +02:00
Make font editor more convenient
This commit is contained in:
@@ -873,7 +873,7 @@ int main(int argc, char * argv[])
|
|||||||
|
|
||||||
#else // FONTEDITOR
|
#else // FONTEDITOR
|
||||||
if(argc <= 1)
|
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]));
|
engine->ShowWindow(new FontEditor(argv[1]));
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
@@ -13,6 +13,7 @@
|
|||||||
#include "gui/interface/Button.h"
|
#include "gui/interface/Button.h"
|
||||||
#include "gui/interface/Mouse.h"
|
#include "gui/interface/Mouse.h"
|
||||||
#include "gui/interface/Keys.h"
|
#include "gui/interface/Keys.h"
|
||||||
|
#include "gui/interface/ScrollPanel.h"
|
||||||
#include "graphics/Graphics.h"
|
#include "graphics/Graphics.h"
|
||||||
|
|
||||||
#ifdef FONTEDITOR
|
#ifdef FONTEDITOR
|
||||||
@@ -254,6 +255,26 @@ void FontEditor::PackData(
|
|||||||
fontRanges.push_back({0, 0});
|
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
|
#define FONT_SCALE 16
|
||||||
FontEditor::FontEditor(ByteString _header):
|
FontEditor::FontEditor(ByteString _header):
|
||||||
ui::Window(ui::Point(0, 0), ui::Point(WINDOWW, WINDOWH)),
|
ui::Window(ui::Point(0, 0), ui::Point(WINDOWW, WINDOWH)),
|
||||||
@@ -339,8 +360,8 @@ FontEditor::FontEditor(ByteString _header):
|
|||||||
currentX += 33;
|
currentX += 33;
|
||||||
showRulers->SetTogglable(true);
|
showRulers->SetTogglable(true);
|
||||||
showRulers->SetToggleState(rulers);
|
showRulers->SetToggleState(rulers);
|
||||||
showRulers->SetActionCallback({ [this, showGrid] {
|
showRulers->SetActionCallback({ [this, showRulers] {
|
||||||
rulers = showGrid->GetToggleState();
|
rulers = showRulers->GetToggleState();
|
||||||
} });
|
} });
|
||||||
AddComponent(showRulers);
|
AddComponent(showRulers);
|
||||||
|
|
||||||
@@ -375,29 +396,41 @@ FontEditor::FontEditor(ByteString _header):
|
|||||||
|
|
||||||
baseline += 18;
|
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->SetMultiline(true);
|
||||||
outputPreview->Appearance.HorizontalAlign = ui::Appearance::AlignLeft;
|
outputPreview->Appearance.HorizontalAlign = ui::Appearance::AlignLeft;
|
||||||
outputPreview->Appearance.VerticalAlign = ui::Appearance::AlignTop;
|
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->SetMultiline(true);
|
||||||
inputPreview->SetInputType(ui::Textbox::Multiline);
|
inputPreview->SetInputType(ui::Textbox::Multiline);
|
||||||
inputPreview->Appearance.HorizontalAlign = ui::Appearance::AlignLeft;
|
inputPreview->Appearance.HorizontalAlign = ui::Appearance::AlignLeft;
|
||||||
inputPreview->Appearance.VerticalAlign = ui::Appearance::AlignTop;
|
inputPreview->Appearance.VerticalAlign = ui::Appearance::AlignTop;
|
||||||
auto textChangedCallback = [this, inputPreview] {
|
auto textChangedCallback = [outputPreview, outputPanel, inputPreview, inputPanel] {
|
||||||
String str = inputPreview->GetText();
|
String str = inputPreview->GetText();
|
||||||
size_t at = 0;
|
size_t at = 0;
|
||||||
StringBuilder text;
|
StringBuilder text;
|
||||||
while(at < str.size())
|
while(at < str.size())
|
||||||
{
|
{
|
||||||
unsigned int ch;
|
unsigned int ch1, ch2;
|
||||||
if(str[at] != ' ')
|
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);
|
if(str[split1.PositionAfter()] == ':')
|
||||||
at = split.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
|
else
|
||||||
{
|
{
|
||||||
@@ -407,16 +440,21 @@ FontEditor::FontEditor(ByteString _header):
|
|||||||
at++;
|
at++;
|
||||||
}
|
}
|
||||||
outputPreview->SetText(text.Build());
|
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 });
|
inputPreview->SetActionCallback({ textChangedCallback });
|
||||||
|
inputPanel->AddChild(inputPreview);
|
||||||
|
|
||||||
StringBuilder input;
|
StringBuilder input;
|
||||||
input << Format::Hex() << Format::Width(2);
|
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))
|
if(ch == 0x80)
|
||||||
input << 0x20 << " ";
|
input << "\n";
|
||||||
input << ch << " ";
|
else if(ch != 0x20)
|
||||||
|
input << " 0a ";
|
||||||
|
input << ch << ":" << (ch + 0x0F);
|
||||||
}
|
}
|
||||||
inputPreview->SetText(input.Build());
|
inputPreview->SetText(input.Build());
|
||||||
textChangedCallback();
|
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)
|
void FontEditor::OnKeyPress(int key, int scan, bool repeat, bool shift, bool ctrl, bool alt)
|
||||||
{
|
{
|
||||||
if (IsFocused(NULL))
|
if (IsFocused(NULL))
|
||||||
{
|
{
|
||||||
switch(scan)
|
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:
|
case SDL_SCANCODE_LEFT:
|
||||||
PrevChar(); break;
|
if(shift)
|
||||||
|
Translate(fontPixels[currentChar], -1, 0);
|
||||||
|
else
|
||||||
|
PrevChar();
|
||||||
|
break;
|
||||||
case SDL_SCANCODE_RIGHT:
|
case SDL_SCANCODE_RIGHT:
|
||||||
PrevChar(); break;
|
if(shift)
|
||||||
|
Translate(fontPixels[currentChar], 1, 0);
|
||||||
|
else
|
||||||
|
NextChar();
|
||||||
|
break;
|
||||||
case SDL_SCANCODE_ESCAPE:
|
case SDL_SCANCODE_ESCAPE:
|
||||||
case SDL_SCANCODE_Q:
|
case SDL_SCANCODE_Q:
|
||||||
if(savedButton->GetToggleState())
|
if(savedButton->GetToggleState())
|
||||||
|
@@ -50,7 +50,6 @@ private:
|
|||||||
|
|
||||||
ui::Textbox *currentCharTextbox;
|
ui::Textbox *currentCharTextbox;
|
||||||
ui::Button *savedButton;
|
ui::Button *savedButton;
|
||||||
ui::Label *outputPreview;
|
|
||||||
|
|
||||||
String::value_type currentChar;
|
String::value_type currentChar;
|
||||||
int fgR, fgG, fgB;
|
int fgR, fgG, fgB;
|
||||||
@@ -69,6 +68,7 @@ private:
|
|||||||
void GrowChar();
|
void GrowChar();
|
||||||
void Render();
|
void Render();
|
||||||
void Save();
|
void Save();
|
||||||
|
void Translate(std::array<std::array<char, MAX_WIDTH>, FONT_H> &, int dx, int dy);
|
||||||
|
|
||||||
public:
|
public:
|
||||||
FontEditor(ByteString header);
|
FontEditor(ByteString header);
|
||||||
|
@@ -41,6 +41,11 @@ namespace ui
|
|||||||
return wrapped_text;
|
return wrapped_text;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int WrappedLines() const
|
||||||
|
{
|
||||||
|
return wrapped_lines;
|
||||||
|
}
|
||||||
|
|
||||||
Index IndexBegin() const
|
Index IndexBegin() const
|
||||||
{
|
{
|
||||||
return Index{ 0, 0, 0 };
|
return Index{ 0, 0, 0 };
|
||||||
|
Reference in New Issue
Block a user