This repository has been archived on 2025-03-20. You can view files and clone it, but cannot push or open issues or pull requests.
The-Powder-Toy/src/gui/game/GOLTool.cpp
2023-04-30 14:22:56 +02:00

209 lines
6.3 KiB
C++

#include "Tool.h"
#include "prefs/GlobalPrefs.h"
#include "client/Client.h"
#include "common/tpt-rand.h"
#include "simulation/GOLString.h"
#include "simulation/Simulation.h"
#include "gui/Style.h"
#include "gui/interface/Button.h"
#include "gui/interface/Label.h"
#include "gui/interface/Textbox.h"
#include "gui/interface/Window.h"
#include "gui/colourpicker/ColourPickerActivity.h"
#include "gui/dialogues/ErrorMessage.h"
#include "gui/game/GameModel.h"
#include "graphics/Graphics.h"
class GOLWindow: public ui::Window
{
ui::Colour highColour, lowColour;
ui::Button *highColourButton, *lowColourButton;
ui::Textbox *nameField, *ruleField;
GameModel &gameModel;
Simulation *sim;
int toolSelection;
void updateGradient();
void validate();
public:
GOLWindow(GameModel &gameModel, Simulation *sim, int toolSelection, int rule, RGB<uint8_t> colour1, RGB<uint8_t> colour2);
virtual ~GOLWindow()
{}
void OnDraw() override;
void OnTryExit(ExitMethod method) override;
};
GOLWindow::GOLWindow(GameModel &gameModel_, Simulation *sim_, int toolSelection, int rule, RGB<uint8_t> colour1, RGB<uint8_t> colour2):
ui::Window(ui::Point(-1, -1), ui::Point(200, 108)),
highColour(colour1.WithAlpha(0xFF)),
lowColour(colour2.WithAlpha(0xFF)),
gameModel(gameModel_),
sim(sim_),
toolSelection(toolSelection)
{
highColour.Alpha = 255;
lowColour.Alpha = 255;
ui::Label * messageLabel = new ui::Label(ui::Point(4, 5), ui::Point(Size.X-8, 14), "Edit custom GOL type");
messageLabel->SetTextColour(style::Colour::InformationTitle);
messageLabel->Appearance.HorizontalAlign = ui::Appearance::AlignLeft;
messageLabel->Appearance.VerticalAlign = ui::Appearance::AlignTop;
AddComponent(messageLabel);
auto *okayButton = new ui::Button(ui::Point(0, Size.Y-17), ui::Point(Size.X, 17), "OK");
okayButton->Appearance.HorizontalAlign = ui::Appearance::AlignLeft;
okayButton->Appearance.VerticalAlign = ui::Appearance::AlignMiddle;
okayButton->Appearance.BorderInactive = ui::Colour(200, 200, 200);
okayButton->SetActionCallback({ [this] {
if (nameField->GetText().length() && ruleField->GetText().length())
{
CloseActiveWindow();
validate();
SelfDestruct();
}
} });
AddComponent(okayButton);
SetOkayButton(okayButton);
nameField = new ui::Textbox(ui::Point(8, 25), ui::Point(Size.X-16, 16), "", "[name]");
nameField->Appearance.HorizontalAlign = ui::Appearance::AlignLeft;
nameField->Appearance.VerticalAlign = ui::Appearance::AlignMiddle;
nameField->SetLimit(7);
AddComponent(nameField);
FocusComponent(nameField);
ruleField = new ui::Textbox(ui::Point(8, 46), ui::Point(Size.X-16, 16), "", "[rule]");
ruleField->Appearance.HorizontalAlign = ui::Appearance::AlignLeft;
ruleField->Appearance.VerticalAlign = ui::Appearance::AlignMiddle;
AddComponent(ruleField);
FocusComponent(ruleField);
highColourButton = new ui::Button(ui::Point(8, 67), ui::Point(16, 16), "");
highColourButton->SetActionCallback({ [this] {
new ColourPickerActivity(highColour, [this](ui::Colour colour) {
highColour = colour;
updateGradient();
});
} });
AddComponent(highColourButton);
lowColourButton = new ui::Button(ui::Point(Size.X - 24, 67), ui::Point(16, 16), "");
lowColourButton->SetActionCallback({ [this] {
new ColourPickerActivity(lowColour, [this](ui::Colour colour) {
lowColour = colour;
updateGradient();
});
} });
AddComponent(lowColourButton);
if (rule)
{
ruleField->SetText(SerialiseGOLRule(rule));
nameField->SetText("");
}
else
{
auto &prefs = GlobalPrefs::Ref();
ruleField->SetText(prefs.Get("CustomGOL.Rule", String("B3/S23")));
nameField->SetText(prefs.Get("CustomGOL.Name", String("CGOL")));
highColour.Red = interfaceRng.between(0x80, 0xFF);
highColour.Green = interfaceRng.between(0x80, 0xFF);
highColour.Blue = interfaceRng.between(0x80, 0xFF);
highColour.Alpha = 0xFF;
lowColour.Red = interfaceRng.between(0x00, 0x7F);
lowColour.Green = interfaceRng.between(0x00, 0x7F);
lowColour.Blue = interfaceRng.between(0x00, 0x7F);
lowColour.Alpha = 0xFF;
}
updateGradient();
MakeActiveWindow();
}
void GOLWindow::updateGradient()
{
highColourButton->Appearance.BackgroundInactive = highColour;
highColourButton->Appearance.BackgroundHover = highColour;
lowColourButton->Appearance.BackgroundInactive = lowColour;
lowColourButton->Appearance.BackgroundHover = lowColour;
}
void GOLWindow::validate()
{
auto nameString = nameField->GetText();
auto ruleString = ruleField->GetText();
if (!ValidateGOLName(nameString))
{
new ErrorMessage("Could not add GOL type", "Invalid name provided");
return;
}
nameString = nameString.ToUpper();
int rule = ParseGOLString(ruleString);
if (rule == -1)
{
new ErrorMessage("Could not add GOL type", "Invalid rule provided");
return;
}
if (sim->GetCustomGOLByRule(rule))
{
new ErrorMessage("Could not add GOL type", "This Custom GoL rule already exists");
return;
}
ruleString = SerialiseGOLRule(rule); // * Make it canonical.
{
auto &prefs = GlobalPrefs::Ref();
Prefs::DeferWrite dw(prefs);
prefs.Set("CustomGOL.Name", nameString);
prefs.Set("CustomGOL.Rule", ruleString);
}
auto color1 = (((highColour.Red << 8) | highColour.Green) << 8) | highColour.Blue;
auto color2 = (((lowColour.Red << 8) | lowColour.Green) << 8) | lowColour.Blue;
if (!AddCustomGol(ruleString, nameString, color1, color2))
{
new ErrorMessage("Could not add GOL type", "Name already taken");
return;
}
gameModel.SelectNextIdentifier = "DEFAULT_PT_LIFECUST_" + nameString.ToAscii();
gameModel.SelectNextTool = toolSelection;
}
void GOLWindow::OnTryExit(ExitMethod method)
{
CloseActiveWindow();
SelfDestruct();
}
void GOLWindow::OnDraw()
{
Graphics * g = GetGraphics();
g->DrawFilledRect(RectSized(Position - Vec2{ 1, 1 }, Size + Vec2{ 2, 2 }), 0x000000_rgb);
g->DrawRect(RectSized(Position, Size), 0xC8C8C8_rgb);
int width = Size.X - 60;
for (int xx = 0; xx < width; ++xx)
{
auto f = xx / (float)width;
for (int yy = 0; yy < 16; ++yy)
{
auto rr = int(highColour.Red * (1.f - f) + lowColour.Red * f);
auto gg = int(highColour.Green * (1.f - f) + lowColour.Green * f);
auto bb = int(highColour.Blue * (1.f - f) + lowColour.Blue * f);
g->DrawPixel(Position + Vec2{ xx + 30, yy + 67 }, RGB<uint8_t>(rr, gg, bb));
}
}
}
void GOLTool::OpenWindow(Simulation *sim, int toolSelection, int rule, RGB<uint8_t> colour1, RGB<uint8_t> colour2)
{
new GOLWindow(gameModel, sim, toolSelection, rule, colour1, colour2);
}