diff --git a/.github/workflows/build-doc.yml b/.github/workflows/build-doc.yml index 53457df1..afa6b4f4 100644 --- a/.github/workflows/build-doc.yml +++ b/.github/workflows/build-doc.yml @@ -2,9 +2,9 @@ name: "Build documentations" on: push: - branches: ["main", "docs"] + branches: ["main"] pull_request: - branches: ["main", "docs"] + branches: ["main"] workflow_dispatch: env: diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 2f7ddfea..88b2214a 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -26,10 +26,14 @@ jobs: fetch-depth: 0 submodules: recursive + - name: Install xmake + uses: xmake-io/github-action-setup-xmake@v1 + with: + xmake-version: latest + - name: Install packages shell: bash run: | - sudo add-apt-repository ppa:xmake-io/xmake sudo apt-get update sudo apt-get install -y \ libx11-dev \ @@ -38,8 +42,7 @@ jobs: libxcursor-dev \ libxi-dev \ libgl1-mesa-dev \ - mesa-common-dev \ - xmake + mesa-common-dev - name: Build shell: bash @@ -70,6 +73,10 @@ jobs: uses: xmake-io/github-action-setup-xmake@v1 with: xmake-version: latest + - name: Configure + run: | + xmake global --clean + xmake config --plat=windows --arch=x64 -y - name: Build shell: pwsh diff --git a/docs/guide.rst b/docs/guide.rst index 66a0ba2a..1d9bb619 100644 --- a/docs/guide.rst +++ b/docs/guide.rst @@ -10,4 +10,5 @@ Learn how to install and use RPG++ to make a simple RPG game! guide/mainconcepts guide/editorlayout guide/editoroptions + guide/projectsettings guide/typesindex \ No newline at end of file diff --git a/docs/guide/editorlayout.rst b/docs/guide/editorlayout.rst index 5273e271..390fb56a 100644 --- a/docs/guide/editorlayout.rst +++ b/docs/guide/editorlayout.rst @@ -45,6 +45,11 @@ Here you can see the title of the opened project, as well as a Playtest button a * **Build** - Export the project. This will result in a .bin file and an executable file in the project's root directory. + .. image:: ../images/rpgpp-projectsettingsbutton.png + :width: 40% + + * **Project Settings** - Open the Project Settings window, where you can change settings about your project. + * `(3)` - **Resources List** Here you can see the resources of the project. The dropdown lets you choose which type of resource do you want to be listed. You can click on any file listed here. The "New Resource" button creates a new resource of the type that is currently chosen in the dropdown. diff --git a/docs/guide/projectsettings.rst b/docs/guide/projectsettings.rst new file mode 100644 index 00000000..99a128fc --- /dev/null +++ b/docs/guide/projectsettings.rst @@ -0,0 +1,45 @@ +Project Settings +================ + +In this window you can change or view settings that will impact the game's window or the gameplay. + +.. image:: ../images/rpgpp-projectsettings.png + :width: 40% + +There are two categories in Project Settings: + +* **Program**: + + This category changes how the program's window behaves. + + * **Title** - The Window's title. + + * **Program Icon** - The icon of the window. + + * **Version** - Version of the game. + + * **Window Width** - Width of the window. + + * **Window Height** - Height of the window. + + * **Is Window Resizeable** - Whether the window will be resizeable. + + * **Window Mode** - windowed, exclusive, minimized, maximized, fullscreen. + + * **Target FPS** - The frames per second that will be targeted. + +* **Game**: + + This category changes the gameplay of the game. + + * **Default Room** - The room in which the player will first spawn. + + * **Player Actor** - The Actor file which will be used for the Player's appearance. + + * **Tile Size** - The tile size in maps. + + * **Debug Draw** - Drawing objects like collision boxes and etc. + + * **Export Image Scales** - What image scales to be exported. + + * **Export Font Sizes** - What font sizes the fonts shall be exported in. \ No newline at end of file diff --git a/docs/guide/resourcetypes/dialogue.rst b/docs/guide/resourcetypes/dialogue.rst index 062b4e12..91443943 100644 --- a/docs/guide/resourcetypes/dialogue.rst +++ b/docs/guide/resourcetypes/dialogue.rst @@ -12,25 +12,32 @@ Example of a Dialogue file (.rdiag): .. code:: json { - "diag": [ - [ - "Xenith", - "I changed the dialogue!", - "0", - "" - ], - [ - "Xenith", - "This is the second line!", - "0", - "" - ], - [ - "Xenith", - "Content", - "0", - "" - ] + "diag":[ + { + "characterName":"Chara", + "hasOptions":false, + "hasPortrait":false, + "imageId":"", + "options":[], + "text":"My dialogue text!" + }, + { + "characterName":"Character", + "hasOptions":true, + "hasPortrait":true, + "imageId":"xenith-portrait.png", + "options":[ + { + "name":"Option 1", + "nextDialogue":"mydiag.rdiag" + }, + { + "name":"Option 2", + "nextDialogue":"diag.rdiag" + } + ], + "text":"Spooky RED text!" + } ] } @@ -55,7 +62,23 @@ The "Add a new line" button will add a new line to this Dialogue. The "Has a portrait?" option sets whether this line will have a portrait image shown for it. If it is on, then you can select an image to be shown. -You can also edit the Character name and the text content for the dialogue line. +You can also edit the Character name and the text content for the dialogue line. Dialogue text supports XML-like tags for formatting the text or achieving other effects. All tags must have a closing tag. + +* **Color tags:** - , , , , , , , , , , , , , , , , , , , , , , , + +* **** - Adds a delay in the typewriter effect in the dialogue UI. + +* **** - Changes the size of the text. It has one property *size* which is to be set to a number. Example usage: ``my text!`` + +* **** - Changes the font of the written text. Example: ``My text!`` + +* **** - Gives the written text a padding. It can be either in pixels of percentage of the dialogue box. + * Example for pixels: ``Padded text in pixels`` + * Example for percentage: ``Padded text in percentage`` + +* **** - Plays a different sound while typing out this text. Example: ``Baa!`` + +* **** - Positions the text on a new line. Example: ``text`` The 'X' button deletes this line. diff --git a/docs/guide/resourcetypes/interactable.rst b/docs/guide/resourcetypes/interactable.rst new file mode 100644 index 00000000..7acd587d --- /dev/null +++ b/docs/guide/resourcetypes/interactable.rst @@ -0,0 +1,44 @@ +Interactable +============ + +======================= +What is an Interactable +======================= + +An Interactable is an object that the player can interact with. It has an attached script that defines its behaviour. It can placed on its own or exist within a Prop or an Actor. + +Example of an Interactable file: + +.. code:: json + + { + "name":"myinter", + "onTouch":false, + "props":{ + "newint":0, + "x":0 + }, + "script":"scripts/test.lua" + } + +==================================== +Creating and editing an Interactable +==================================== + +To create an Interactable, you just need to give it a name. + +.. image:: ../../images/rpgpp-createinteractable.png + :width: 40% + +Then you can edit its properties. + +.. image:: ../../images/rpgpp-interactableview.png + :width: 40% + +* **Display Name** - Sets a friendly name that will show up only in the editor. + +* **Script** - Sets a Lua script that will define the Interactable's behaviour. THe script must have an interact() function. + +* **On Touch?** - Whether this Interactable will trigger when the player collides with the interactable. + +On top of that, you can add or remove your own properties for the Interactable. diff --git a/docs/guide/resourcetypes/prop.rst b/docs/guide/resourcetypes/prop.rst index d52cb73d..5ead9e8d 100644 --- a/docs/guide/resourcetypes/prop.rst +++ b/docs/guide/resourcetypes/prop.rst @@ -52,3 +52,5 @@ You can also change the image for this Prop. Atlas Rect refers to the portion of the Prop Image, that will be shown. Collision Rect refers to the position and size of the collision, relative to the top left corner of the Prop. Both properties have X and Y for position and W and H for size. + +You can also see a preview of your Prop under the properties. It will show how the Prop will actually look like in-game. diff --git a/docs/guide/typesindex.rst b/docs/guide/typesindex.rst index aa52e316..dc658089 100644 --- a/docs/guide/typesindex.rst +++ b/docs/guide/typesindex.rst @@ -6,4 +6,5 @@ Resource Types resourcetypes/room resourcetypes/actor resourcetypes/dialogue - resourcetypes/prop \ No newline at end of file + resourcetypes/prop + resourcetypes/interactable \ No newline at end of file diff --git a/docs/images/rpgpp-createinteractable.png b/docs/images/rpgpp-createinteractable.png new file mode 100644 index 00000000..ba9df1b7 Binary files /dev/null and b/docs/images/rpgpp-createinteractable.png differ diff --git a/docs/images/rpgpp-editeddialogueline.png b/docs/images/rpgpp-editeddialogueline.png index 7a9d50ff..04e67d6e 100644 Binary files a/docs/images/rpgpp-editeddialogueline.png and b/docs/images/rpgpp-editeddialogueline.png differ diff --git a/docs/images/rpgpp-editorlayout.png b/docs/images/rpgpp-editorlayout.png index 917953e3..177e1a13 100644 Binary files a/docs/images/rpgpp-editorlayout.png and b/docs/images/rpgpp-editorlayout.png differ diff --git a/docs/images/rpgpp-interactableview.png b/docs/images/rpgpp-interactableview.png new file mode 100644 index 00000000..7214da84 Binary files /dev/null and b/docs/images/rpgpp-interactableview.png differ diff --git a/docs/images/rpgpp-newdialogueline.png b/docs/images/rpgpp-newdialogueline.png index d25b0b05..34543545 100644 Binary files a/docs/images/rpgpp-newdialogueline.png and b/docs/images/rpgpp-newdialogueline.png differ diff --git a/docs/images/rpgpp-projectmenu.png b/docs/images/rpgpp-projectmenu.png index 66b8707b..0da14ec4 100644 Binary files a/docs/images/rpgpp-projectmenu.png and b/docs/images/rpgpp-projectmenu.png differ diff --git a/docs/images/rpgpp-projectsettings.png b/docs/images/rpgpp-projectsettings.png new file mode 100644 index 00000000..83d5f187 Binary files /dev/null and b/docs/images/rpgpp-projectsettings.png differ diff --git a/docs/images/rpgpp-projectsettingsbutton.png b/docs/images/rpgpp-projectsettingsbutton.png new file mode 100644 index 00000000..faaf97ab Binary files /dev/null and b/docs/images/rpgpp-projectsettingsbutton.png differ diff --git a/docs/images/rpgpp-propview.png b/docs/images/rpgpp-propview.png index aa9c7717..3880b6c7 100644 Binary files a/docs/images/rpgpp-propview.png and b/docs/images/rpgpp-propview.png differ diff --git a/include/actor.hpp b/include/actor.hpp index d6c5d5b3..e3159521 100644 --- a/include/actor.hpp +++ b/include/actor.hpp @@ -1,37 +1,40 @@ #ifndef _RPGPP_ACTOR_H #define _RPGPP_ACTOR_H -#include "atlasTile.hpp" -#include "gamedata.hpp" -#include "saveable.hpp" -#include "tileset.hpp" +#include + #include #include #include #include -#include #include +#include "atlasTile.hpp" +#include "gamedata.hpp" +#include "interactable.hpp" +#include "saveable.hpp" +#include "tileset.hpp" + using json = nlohmann::json; #define RPGPP_MAX_DIRECTION 7 /** Direction enum, representing an animation state. */ enum Direction : short { - RPGPP_DOWN_IDLE = 0, ///< Down Idle state. - RPGPP_DOWN = 1, ///< Down state. - RPGPP_UP_IDLE = 2, ///< Up Idle state. - RPGPP_UP = 3, ///< Up state. - RPGPP_LEFT_IDLE = 4, ///< Left Idle state. - RPGPP_LEFT = 5, ///< Left state. - RPGPP_RIGHT_IDLE = 6, ///< Right Idle state. - RPGPP_RIGHT = 7 ///< Right state. + RPGPP_DOWN_IDLE = 0, ///< Down Idle state. + RPGPP_DOWN = 1, ///< Down state. + RPGPP_UP_IDLE = 2, ///< Up Idle state. + RPGPP_UP = 3, ///< Up state. + RPGPP_LEFT_IDLE = 4, ///< Left Idle state. + RPGPP_LEFT = 5, ///< Left state. + RPGPP_RIGHT_IDLE = 6, ///< Right Idle state. + RPGPP_RIGHT = 7 ///< Right state. }; /** The Actor class represents an Actor in the game's world. * @see [Direction](Direction.md) */ class Actor : public ISaveable { - private: +private: std::string sourcePath; /** The used TileSet for this Actor's sprites. */ std::unique_ptr tileSet; @@ -55,16 +58,19 @@ class Actor : public ISaveable { Direction currentAnimation; Direction lastAnimation; bool tempAnimIsPlayed = false; + /** Whether this Actor has an Interactable. */ + bool ownsInteractable = false; + /** A smart pointer, owning an Interactable. */ + std::unique_ptr interactable; - public: +public: /** Empty constructor. */ Actor() = default; /** Constructor that takes a path to the .ractor file. */ Actor(const std::string &fileName); /** Constructor that takes a TileSet, the atlas position of the tile to use, * and the path to the TileSet. */ - Actor(std::unique_ptr tileSet, Vector2 atlasPos, - std::string tileSetSource); + Actor(std::unique_ptr tileSet, Vector2 atlasPos, std::string tileSetSource); /** Constructor that takes an ActorBin binary structure */ Actor(const ActorBin &bin); /** Dump this Actor's data to a nlohmann::json object. */ @@ -114,6 +120,8 @@ class Actor : public ISaveable { /** Get the collision rectangle of this Actor if it was moved by the * velocity vector */ Rectangle getCollisionRect(Vector2 velocity) const; + /** Get the collision Rectangle of this Actor */ + Rectangle getCollisionRect() const; /** Get collision center point. */ Vector2 getCollisionCenter() const; /** Add a frame in the chosen animation. The frame represents an atlas tile @@ -125,8 +133,7 @@ class Actor : public ISaveable { * TileSet. */ void setAnimationFrame(Direction id, int frameIndex, Vector2 atlasTile); /** Add multiple frames to the chosen animation. */ - void addAnimationFrames(Direction id, - const std::vector> &frames); + void addAnimationFrames(Direction id, const std::vector> &frames); /** Temporarily play an animation */ void playAnimation(Direction id); /** Check whether a temporary animation is playing */ @@ -139,13 +146,18 @@ class Actor : public ISaveable { std::array, 8> getAnimationsRaw() const; /** Get a specific animation */ std::vector getAnimationRaw(Direction id) const; - /** Get the collision Rectangle of this Actor */ - Rectangle getCollisionRect() const; /** Set the Actor's collision Rectangle */ void setCollisionRect(Rectangle rect); + /** Whether this Actor has an Interactable. */ + bool hasInteractable(); + /** Set the 'ownsInteractable' flag. */ + void setHasInteractable(bool value); + /** Get a pointer to this Actor's Interactable. */ + Interactable *getInteractable(); + /** Add an Interactable using an interactable file. */ + void setInteractableFromPath(const std::string &interPath); }; -Vector2 calcActorTilePos(Vector2 newPosition, Vector2 worldTileSize, - TileSet *tileSet); +Vector2 calcActorTilePos(Vector2 newPosition, Vector2 worldTileSize, TileSet *tileSet); #endif diff --git a/include/actorContainer.hpp b/include/actorContainer.hpp index e06bab28..38504b41 100644 --- a/include/actorContainer.hpp +++ b/include/actorContainer.hpp @@ -4,10 +4,10 @@ #include "actor.hpp" class ActorContainer { - private: +private: std::map> actors; - public: +public: /** Construct the actor container. */ ActorContainer(); /** Get the map itself */ @@ -15,12 +15,11 @@ class ActorContainer { /** Get an Actor with the specified name */ Actor &getActor(const std::string &name); /** Add a new Actor with a name from the GameBin and an in-room name*/ - void addActor(Vector2 pos, const std::string &typeName, - const std::string &roomName); + void addActor(Vector2 pos, const std::string &typeName, const std::string &roomName); /** Remove an Actor */ void removeActor(const std::string &roomName); /** Check whether an Actor with such an in-room name exists. */ bool actorExists(const std::string &roomName); }; -#endif // !_RPGPP_ACTORCONTAINER_H +#endif // !_RPGPP_ACTORCONTAINER_H diff --git a/include/atlasTile.hpp b/include/atlasTile.hpp index 6baaa43f..2afe57ad 100644 --- a/include/atlasTile.hpp +++ b/include/atlasTile.hpp @@ -7,13 +7,13 @@ * Represents a source atlas tile from a TileSet. */ class AtlasTile { - private: +private: /** Pointer to the used Texture */ Texture *texture; /** The atlas (source) coordinates from the TileSet. */ Vector2 atlasCoords; - public: +public: /** * Empty constructor */ diff --git a/include/baseContainer.hpp b/include/baseContainer.hpp index 9d1345a1..d57da766 100644 --- a/include/baseContainer.hpp +++ b/include/baseContainer.hpp @@ -1,28 +1,25 @@ #ifndef _RPGPP_BASECONTAINER_H #define _RPGPP_BASECONTAINER_H -#include "conversion.hpp" -#include "gamedata.hpp" -#include "raylib.h" #include #include -template class BaseContainer { +#include "conversion.hpp" +#include "gamedata.hpp" +#include "raylib.h" - protected: +template +class BaseContainer { +protected: /** The list of objects kept inside of this container. */ std::map objects = {}; - public: +public: BaseContainer() {} /** Pushes an object to the map. */ - void pushObject(IVector pos, T obj) { - this->objects.try_emplace(pos, std::move(obj)); - } - void pushObjectVec2(Vector2 pos, T obj) { - pushObject(fromVector2(pos), obj); - } + void pushObject(IVector pos, T obj) { this->objects.try_emplace(pos, std::move(obj)); } + void pushObjectVec2(Vector2 pos, T obj) { pushObject(fromVector2(pos), obj); } /** Remove an object existing at a position. */ void removeObject(IVector pos) { auto key = this->objects.find(pos); @@ -32,20 +29,15 @@ template class BaseContainer { } void removeObjectVec2(Vector2 pos) { removeObject(fromVector2(pos)); } /** Check if an object exists at specified position. */ - bool objectExistsAtPosition(IVector pos) { - return this->objects.find(pos) != this->objects.end(); - } - bool objectExistsAtPositionVec2(Vector2 pos) { - return objectExistsAtPosition(fromVector2(pos)); - } + bool objectExistsAtPosition(IVector pos) { return this->objects.find(pos) != this->objects.end(); } + bool objectExistsAtPositionVec2(Vector2 pos) { return objectExistsAtPosition(fromVector2(pos)); } /** Gets the object at a specified IVector Position. */ T &getObjectAtPosition(IVector pos) { - if (this->objects.find(pos) != this->objects.end()) - return this->objects[pos]; + if (this->objects.find(pos) != this->objects.end()) return this->objects[pos]; throw std::out_of_range("key not found!"); } /** Get a reference to the whole object map. */ std::map &getObjects() { return this->objects; } }; -#endif // !_RPGPP_BASECONTAINER_H +#endif // !_RPGPP_BASECONTAINER_H diff --git a/include/collisionsContainer.hpp b/include/collisionsContainer.hpp index ba701e30..1fefb695 100644 --- a/include/collisionsContainer.hpp +++ b/include/collisionsContainer.hpp @@ -1,13 +1,14 @@ #ifndef _RPGPP_COLLISIONSCONTAINER_H #define _RPGPP_COLLISIONSCONTAINER_H +#include + #include "baseContainer.hpp" #include "gamedata.hpp" -#include /** A container of collision tiles to be used by a Room */ class CollisionsContainer : public BaseContainer { - public: +public: /** Empty constructor */ CollisionsContainer(); /** Add a collision */ diff --git a/include/colorRect.hpp b/include/colorRect.hpp index 8022a3e1..adab37c2 100644 --- a/include/colorRect.hpp +++ b/include/colorRect.hpp @@ -1,15 +1,16 @@ #ifndef _RPGPP_COLORRECT_H #define _RPGPP_COLORRECT_H -#include "uiElement.hpp" #include +#include "uiElement.hpp" + class ColorRect : public UIElement { - private: +private: Rectangle rect; Color color; - public: +public: ColorRect(); explicit ColorRect(Rectangle rect); diff --git a/include/conversion.hpp b/include/conversion.hpp index 14339e54..36e9ed1e 100644 --- a/include/conversion.hpp +++ b/include/conversion.hpp @@ -6,4 +6,4 @@ Vector2 fromIVector(const IVector &other); IVector fromVector2(const Vector2 &other); -#endif // !_RPGPP_CONVERSION_H \ No newline at end of file +#endif // !_RPGPP_CONVERSION_H \ No newline at end of file diff --git a/include/dialogueBalloon.hpp b/include/dialogueBalloon.hpp index 0d2c0e64..16798715 100644 --- a/include/dialogueBalloon.hpp +++ b/include/dialogueBalloon.hpp @@ -2,12 +2,28 @@ #define _RPGPP_DIALOGUEBALLOON_H #include + #include #include +enum DialoguePaddingMode { PADDING_PX, PADDING_PERCENT }; + struct DialogueTextSection { std::string key; std::string text; + Color textColor = WHITE; + int textSize = 13; + std::string font = "LanaPixel"; + float delay = 0.0f; + std::string sound = "Text 1"; + float padding = 0.0f; + DialoguePaddingMode paddingMode = PADDING_PX; + bool newline = false; +}; + +struct DialogueOption { + std::string title; + std::string nextDialogue; }; struct DialogueLine { @@ -16,6 +32,8 @@ struct DialogueLine { bool hasPortrait; std::string imageId; std::vector sections; + bool hasOptions = false; + std::vector options; }; struct DialogueBin { @@ -24,32 +42,45 @@ struct DialogueBin { }; class DialogueBalloon { - private: +private: + std::string fontName = "LanaPixel"; + Font font; Rectangle rect; Rectangle textRect; Rectangle textPortraitRect; + Rectangle optionsRect; DialogueBin dialogue; std::string text; DialogueTextSection sectionText; + bool firstCharTyped; + bool finishedTyping = false; bool active; int frameCounter; int charIndex; int lineIndex; int sectionIndex; - Color textColor; int lastSectionLen; + + Color textColor; Vector2 textPos; + bool delay = false; + float delayDuration = 0.0f; + int hoveredOption = 0; + float padding = 0.0f; + float maxLineHeight = 0.0f; + bool appliedTag = false; + void drawPortrait() const; - public: +public: DialogueBalloon(); DialogueBalloon(Rectangle rect); void update(); void draw(); void showDialogue(const DialogueBin &newDialogue); void hideDialogue(); - void charP(Vector2 charMeasure, const char *c, Color color); + void charP(Vector2 charMeasure, const char *c, DialogueLine &textLine, DialogueTextSection &textSection); }; #endif diff --git a/include/dialogueParser.hpp b/include/dialogueParser.hpp index 99f26ca9..9b4c9e45 100644 --- a/include/dialogueParser.hpp +++ b/include/dialogueParser.hpp @@ -2,10 +2,14 @@ #define _RPGPP_EDITOR_DIALOGUEPARSER_H #include +#include #include #include +#include using json = nlohmann::json; +std::vector getColorTypes(); +std::map &getColors(); std::vector parseDialogueContent(const std::string &t); #endif \ No newline at end of file diff --git a/include/editor/actions/action.hpp b/include/editor/actions/action.hpp index 8a04ebf7..22415aea 100644 --- a/include/editor/actions/action.hpp +++ b/include/editor/actions/action.hpp @@ -2,7 +2,7 @@ #define _RPGPP_ACTION_H class Action { - public: +public: bool executeOnAdd = true; Action() = default; virtual void execute() {}; diff --git a/include/editor/actions/editTileAction.hpp b/include/editor/actions/editTileAction.hpp index 9fc43afa..1060c516 100644 --- a/include/editor/actions/editTileAction.hpp +++ b/include/editor/actions/editTileAction.hpp @@ -5,7 +5,7 @@ #include "views/tileSetView.hpp" class EditTileAction : public MapAction { - public: +public: EditTileAction(MapActionData a); void execute() override; void undo() override; diff --git a/include/editor/actions/eraseTileAction.hpp b/include/editor/actions/eraseTileAction.hpp index 54716f00..e7847216 100644 --- a/include/editor/actions/eraseTileAction.hpp +++ b/include/editor/actions/eraseTileAction.hpp @@ -4,7 +4,7 @@ #include "mapAction.hpp" class EraseTileAction : public MapAction { - public: +public: EraseTileAction(MapActionData data); void execute() override; void undo() override; diff --git a/include/editor/actions/mapAction.hpp b/include/editor/actions/mapAction.hpp index fa99dcac..994e7c1a 100644 --- a/include/editor/actions/mapAction.hpp +++ b/include/editor/actions/mapAction.hpp @@ -1,13 +1,14 @@ #ifndef _RPGPP_MAPACTION_H #define _RPGPP_MAPACTION_H -#include "action.hpp" -#include "room.hpp" -#include "views/roomView.hpp" #include #include #include +#include "action.hpp" +#include "room.hpp" +#include "views/roomView.hpp" + struct MapActionData { RoomView *view; Room *room; @@ -21,7 +22,7 @@ struct MapActionData { }; class MapAction : public Action { - public: +public: std::unique_ptr prevRoom; MapAction(MapActionData a) { data = a; diff --git a/include/editor/actions/placeTileAction.hpp b/include/editor/actions/placeTileAction.hpp index 433d8fa4..0c7b6c7a 100644 --- a/include/editor/actions/placeTileAction.hpp +++ b/include/editor/actions/placeTileAction.hpp @@ -4,7 +4,7 @@ #include "mapAction.hpp" class PlaceTileAction : public MapAction { - public: +public: PlaceTileAction(MapActionData a); void execute() override; void undo() override; diff --git a/include/editor/actions/startPointAction.hpp b/include/editor/actions/startPointAction.hpp index 4e87c375..c8ab595c 100644 --- a/include/editor/actions/startPointAction.hpp +++ b/include/editor/actions/startPointAction.hpp @@ -3,7 +3,7 @@ #include "actions/mapAction.hpp" class StartPointAction : public MapAction { - public: +public: StartPointAction(MapActionData data); void execute() override; void undo() override; diff --git a/include/editor/bindTranslation.hpp b/include/editor/bindTranslation.hpp index 838448d8..eb5f3a01 100644 --- a/include/editor/bindTranslation.hpp +++ b/include/editor/bindTranslation.hpp @@ -1,17 +1,22 @@ -#include "editor.hpp" -#include "services/translationService.hpp" +#ifndef _RPGPP_BINDTRANSLATION_H +#define _RPGPP_BINDTRANSLATION_H + #include #include +#include "editor.hpp" +#include "services/translationService.hpp" + class TSConnection { - public: +public: TSConnection(TranslationService::ListenerID id) : id(id) {} ~TSConnection() { Editor::instance->getTranslations().removeListener(id); } - private: +private: TranslationService::ListenerID id; }; +// Binds a widget's text to a translation key, updating it whenever the translation changes. template void bindTranslation(std::shared_ptr widget, const std::string &key, void (WidgetType::*setter)(const tgui::String &)) { @@ -22,44 +27,34 @@ void bindTranslation(std::shared_ptr widget, const std::string &key, (widget.get()->*setter)(ts.getKey(key)); auto id = ts.addListener( - [weakWidget, key, setter](TranslationService &ts, - TranslationService::ListenerID id, - bool checkingAlive) { + [weakWidget, key, setter](TranslationService &ts, TranslationService::ListenerID id, bool checkingAlive) { if (auto w = weakWidget.lock()) { - if (!checkingAlive) - (w.get()->*setter)(ts.getKey(key)); + if (!checkingAlive) (w.get()->*setter)(ts.getKey(key)); return true; } else { return false; } }); - - // TODO: Implement a cleaner way to detect when the widget is destroyed, and - // call - // Editor::instance->getTranslations().removeListener(id); - // There's currently an issue on TGUI's repo to add support for callback - // when a widget gets destroyed https://github.com/texus/TGUI/issues/326 } +// Binds a custom callback to a widget, and calling it whenever the translation changes. +// The callback function provides references to the widget and the translation service. template -void bindCustomTranslation( - std::shared_ptr widget, - std::function widget, - TranslationService &)> - cb) { +void bindTranslationWithCallback(std::shared_ptr widget, + std::function widget, TranslationService &)> cb) { auto &ts = Editor::instance->getTranslations(); std::weak_ptr weakWidget = widget; cb(widget, ts); - auto id = ts.addListener([weakWidget, cb](TranslationService &ts, - TranslationService::ListenerID id, - bool checkingAlive) { - if (auto w = weakWidget.lock()) { - if (!checkingAlive) - cb(w, ts); - return true; - } else { - return false; - } - }); + auto id = + ts.addListener([weakWidget, cb](TranslationService &ts, TranslationService::ListenerID id, bool checkingAlive) { + if (auto w = weakWidget.lock()) { + if (!checkingAlive) cb(w, ts); + return true; + } else { + return false; + } + }); } + +#endif diff --git a/include/editor/childWindows/aboutWindow.hpp b/include/editor/childWindows/aboutWindow.hpp index 45f933e7..6af5605a 100644 --- a/include/editor/childWindows/aboutWindow.hpp +++ b/include/editor/childWindows/aboutWindow.hpp @@ -3,7 +3,7 @@ #include "childWindows/popupWindow.hpp" class AboutWindow : public PopupWindow { - public: +public: AboutWindow(); }; diff --git a/include/editor/childWindows/addDelayDialogueWindow.hpp b/include/editor/childWindows/addDelayDialogueWindow.hpp new file mode 100644 index 00000000..82b7ba48 --- /dev/null +++ b/include/editor/childWindows/addDelayDialogueWindow.hpp @@ -0,0 +1,19 @@ +#ifndef RPGPP_ADDDELAYDIALOGUEWINDOW_HPP +#define RPGPP_ADDDELAYDIALOGUEWINDOW_HPP + +#include "TGUI/Widgets/SpinControl.hpp" +#include "childWindows/popupWindow.hpp" +#include "widgets/dialogueEditor.hpp" +class AddDelayDialogueWindow : public PopupWindow { +private: + std::shared_ptr editor; + + tgui::SpinControl::Ptr delaySpin; + +public: + AddDelayDialogueWindow(); + + void open(std::shared_ptr editor); +}; + +#endif // RPGPP_ADDDELAYDIALOGUEWINDOW_HPP diff --git a/include/editor/childWindows/addDialogueOptionWindow.hpp b/include/editor/childWindows/addDialogueOptionWindow.hpp new file mode 100644 index 00000000..4a40f45a --- /dev/null +++ b/include/editor/childWindows/addDialogueOptionWindow.hpp @@ -0,0 +1,16 @@ +#ifndef _RPGPP_CHILDWINDOWS_ADDDIALOGUEOPTIONWINDOW_H +#define _RPGPP_CHILDWINDOWS_ADDDIALOGUEOPTIONWINDOW_H + +#include "childWindows/popupWindow.hpp" +#include "dialogue.hpp" +#include "fileViews/dialogueFileView.hpp" + +class AddDialogueOptionWindow : public PopupWindow { +public: + Dialogue *dialogue; + int lineIndex; + DialogueFileView *fileView; + AddDialogueOptionWindow(); +}; + +#endif \ No newline at end of file diff --git a/include/editor/childWindows/colorSelectWindow.hpp b/include/editor/childWindows/colorSelectWindow.hpp new file mode 100644 index 00000000..10a710ef --- /dev/null +++ b/include/editor/childWindows/colorSelectWindow.hpp @@ -0,0 +1,18 @@ +#ifndef _RPGPP_COLORSELECTWINDOW_HPP +#define _RPGPP_COLORSELECTWINDOW_HPP + +#include + +#include "childWindows/popupWindow.hpp" +#include "widgets/dialogueEditor.hpp" +class ColorSelectWindow : public PopupWindow { +private: + std::shared_ptr editor; + +public: + ColorSelectWindow(); + + void open(std::shared_ptr editor); +}; + +#endif \ No newline at end of file diff --git a/include/editor/childWindows/editDialogueOptionWindow.hpp b/include/editor/childWindows/editDialogueOptionWindow.hpp new file mode 100644 index 00000000..0177867b --- /dev/null +++ b/include/editor/childWindows/editDialogueOptionWindow.hpp @@ -0,0 +1,24 @@ +#ifndef _RPGPP_CHILDWINDOWS_EDITDIALOGUEOPTIONWINDOW_H +#define _RPGPP_CHILDWINDOWS_EDITDIALOGUEOPTIONWINDOW_H + +#include "childWindows/popupWindow.hpp" +#include "dialogue.hpp" +#include "fileViews/dialogueFileView.hpp" +#include "widgets/propertyFields/fileField.hpp" +#include "widgets/propertyFields/textField.hpp" + +class EditDialogueOptionWindow : public PopupWindow { +public: + Dialogue *dialogue; + int lineIndex; + int optionIndex; + DialogueFileView *fileView; + + TextField::Ptr nameField; + FileField::Ptr dialogueField; + + EditDialogueOptionWindow(); + void setup(Dialogue *dialogue, int lineIndex, int optionIndex); +}; + +#endif \ No newline at end of file diff --git a/include/editor/childWindows/editListFieldWindow.hpp b/include/editor/childWindows/editListFieldWindow.hpp new file mode 100644 index 00000000..5496ef6f --- /dev/null +++ b/include/editor/childWindows/editListFieldWindow.hpp @@ -0,0 +1,151 @@ +#ifndef _RPGPP_EDITLISTFIELDWINDOW_H +#define _RPGPP_EDITLISTFIELDWINDOW_H + +#include + +#include "TGUI/String.hpp" +#include "TGUI/Widgets/Button.hpp" +#include "TGUI/Widgets/GrowVerticalLayout.hpp" +#include "TGUI/Widgets/Panel.hpp" +#include "TGUI/Widgets/ScrollablePanel.hpp" +#include "bindTranslation.hpp" +#include "childWindows/popupWindow.hpp" +#include "listHelper.hpp" +#include "nlohmann/json_fwd.hpp" +#include "raylib.h" +#include "widgets/propertiesBox.hpp" +#include "widgets/propertyFields/intField.hpp" +#include "widgets/propertyFields/listField.hpp" +#include "widgets/propertyFields/textField.hpp" + +template +class EditListFieldWindow : public PopupWindow { +public: + tgui::GrowVerticalLayout::Ptr layout; + std::vector *list; + ListField *field; + EditListFieldWindow() : PopupWindow("Edit List..") { + bindTranslation(this->currentWindow, "dialog.edit_list_field.title", &tgui::ChildWindow::setTitle); + list = nullptr; + currentWindow->setSize(280, 180); + + auto panel = tgui::Panel::create(); + panel->getRenderer()->setPadding({4, 4}); + + auto addButton = tgui::Button::create(); + bindTranslation(addButton, "dialog.edit_list_field.add", &tgui::Button::setText); + addButton->setPosition(0, 0); + addButton->setSize("100%", "10%"); + addButton->onPress([this] { + addItem(); + field->value->setText(VecToString(*list)); + }); + panel->add(addButton); + + auto scrollablePanel = tgui::ScrollablePanel::create({"100%", "80%"}); + scrollablePanel->setPosition(0, "10%"); + + layout = tgui::GrowVerticalLayout::create(); + layout->getRenderer()->setSpaceBetweenWidgets(4); + scrollablePanel->add(layout); + + auto closeButton = tgui::Button::create(); + bindTranslation(closeButton, "dialog.edit_list_field.close", &tgui::Button::setText); + closeButton->setText("Close"); + closeButton->setPosition(0, "90%"); + closeButton->setSize("100%", "10%"); + closeButton->onClick([this] { close(); }); + panel->add(closeButton); + + panel->add(scrollablePanel); + currentWindow->add(panel); + } + + void addItem(int index = -1); + + void setup(std::vector *listPtr) { + this->list = listPtr; + this->layout->removeAllWidgets(); + int i = 0; + for (auto &item : *list) { + addItem(i); + i++; + } + } +}; + +template <> +inline void EditListFieldWindow::addItem(int index) { + if (index == -1) { + auto &newItem = list->emplace_back(); + auto newField = TextField::create(); + newField->setSize({"100%", 24}); + newField->label->setText(TextFormat("[%i]", list->size() - 1)); + newField->value->onTextChange([&newItem, this](const tgui::String &text) { + newItem = text.toStdString(); + field->value->setText(VecToString(*list)); + }); + layout->add(newField); + } else { + auto &newItem = list->at(index); + auto newField = TextField::create(); + newField->setSize({"100%", 24}); + newField->label->setText(TextFormat("[%i]", index)); + newField->value->setText(newItem); + newField->value->onTextChange([&newItem, this](const tgui::String &text) { + newItem = text.toStdString(); + field->value->setText(VecToString(*list)); + }); + layout->add(newField); + } +} + +template <> +inline void EditListFieldWindow::addItem(int index) { + if (index == -1) { + auto &newItem = list->emplace_back(); + index = list->size() - 1; + + auto newField = IntField::create(); + newField->setSize({"100%", 24}); + newField->label->setText(TextFormat("[%i]", index)); + newField->value->setMinimum(0); + newField->value->setMaximum(100); + newField->value->onValueChange([&newItem, this](int value) { + newItem = value; + field->value->setText(VecToString(*list)); + }); + newField->value->setValue(newItem); + newField->enableRemoving(); + newField->remove->onClick([this, &newField, index] { + list->erase(list->begin() + index); + layout->remove(newField); + field->value->setText(VecToString(*list)); + }); + + layout->add(newField); + } else { + auto &newItem = list->at(index); + + auto newField = IntField::create(); + newField->setSize({"100%", 24}); + newField->label->setText(TextFormat("[%i]", index)); + newField->value->setMinimum(0); + newField->value->setMaximum(100); + newField->value->onValueChange([&newItem, this](int value) { + newItem = value; + field->value->setText(VecToString(*list)); + }); + newField->value->setValue(newItem); + newField->enableRemoving(); + newField->remove->onClick([this, &newField, index] { + list->erase(list->begin() + index); + setup(list); + field->value->setText(VecToString(*list)); + }); + + layout->add(newField); + } +} + +#endif \ No newline at end of file diff --git a/include/editor/childWindows/editPropWindow.hpp b/include/editor/childWindows/editPropWindow.hpp new file mode 100644 index 00000000..023dfe8c --- /dev/null +++ b/include/editor/childWindows/editPropWindow.hpp @@ -0,0 +1,24 @@ +#ifndef _RPGPP_EDITPROPWINDOW_H +#define _RPGPP_EDITPROPWINDOW_H + +#include "TGUI/Widgets/ComboBox.hpp" +#include "TGUI/Widgets/Label.hpp" +#include "childWindows/popupWindow.hpp" +#include "interactable.hpp" +#include "nlohmann/json_fwd.hpp" +#include "widgets/propertiesBox.hpp" + +class EditPropWindow : public PopupWindow { +public: + nlohmann::json *props; + PropertiesBox *box; + Interactable *interactable; + std::string propName; + + tgui::Label::Ptr nameLabel; + SelectField::Ptr dropdown; + + EditPropWindow(); +}; + +#endif diff --git a/include/editor/childWindows/newPropWindow.hpp b/include/editor/childWindows/newPropWindow.hpp new file mode 100644 index 00000000..f1ebc12b --- /dev/null +++ b/include/editor/childWindows/newPropWindow.hpp @@ -0,0 +1,17 @@ +#ifndef _RPGPP_NEWPROPWINDOW_H +#define _RPGPP_NEWPROPWINDOW_H + +#include "childWindows/popupWindow.hpp" +#include "interactable.hpp" +#include "nlohmann/json_fwd.hpp" +#include "widgets/propertiesBox.hpp" + +class NewPropWindow : public PopupWindow { +public: + nlohmann::json *props; + PropertiesBox *box; + Interactable *interactable; + NewPropWindow(); +}; + +#endif \ No newline at end of file diff --git a/include/editor/childWindows/popupWindow.hpp b/include/editor/childWindows/popupWindow.hpp index 7ce23c6a..273bb1f3 100644 --- a/include/editor/childWindows/popupWindow.hpp +++ b/include/editor/childWindows/popupWindow.hpp @@ -1,17 +1,18 @@ #ifndef RPGPP_POPUPWINDOW_H #define RPGPP_POPUPWINDOW_H -#include "TGUI/Widgets/ChildWindow.hpp" #include + +#include "TGUI/Widgets/ChildWindow.hpp" class PopupWindow { - public: +public: bool windowIsOpen = false; tgui::ChildWindow::Ptr currentWindow; - PopupWindow(const std::string &title); + explicit PopupWindow(const std::string &title); ~PopupWindow() { close(); }; - void open(); + virtual void open(); void close(); }; diff --git a/include/editor/childWindows/projectSettingsPanel/game.hpp b/include/editor/childWindows/projectSettingsPanel/game.hpp new file mode 100644 index 00000000..1213ff78 --- /dev/null +++ b/include/editor/childWindows/projectSettingsPanel/game.hpp @@ -0,0 +1,28 @@ +#ifndef _RPGPP_PROJECTSETTINGSPANEL_GAME_H +#define _RPGPP_PROJECTSETTINGSPANEL_GAME_H + +#include + +#include "childWindows/editListFieldWindow.hpp" +#include "childWindows/settingsPanel/base.hpp" +#include "widgets/propertyFields/boolField.hpp" +#include "widgets/propertyFields/fileField.hpp" +#include "widgets/propertyFields/intField.hpp" +#include "widgets/propertyFields/listField.hpp" + +class ProjectSettingsPanelGame : public SettingsPanelBase { +public: + FileField::Ptr defaultRoom; + FileField::Ptr playerActor; + IntField::Ptr tileSize; + BoolField::Ptr debugDraw; + ListField::Ptr exportImageScales; + ListField::Ptr exportFontSizes; + + std::unique_ptr> editListFieldWindow; + + ProjectSettingsPanelGame(tgui::TabContainer::Ptr tabContainer); + void setup(Project *project); +}; + +#endif \ No newline at end of file diff --git a/include/editor/childWindows/projectSettingsPanel/program.hpp b/include/editor/childWindows/projectSettingsPanel/program.hpp new file mode 100644 index 00000000..49669cc2 --- /dev/null +++ b/include/editor/childWindows/projectSettingsPanel/program.hpp @@ -0,0 +1,26 @@ +#ifndef _RPGPP_PROJECTSETTINGSPANEL_PROGRAM_H +#define _RPGPP_PROJECTSETTINGSPANEL_PROGRAM_H + +#include "childWindows/settingsPanel/base.hpp" +#include "widgets/propertyFields/boolField.hpp" +#include "widgets/propertyFields/fileField.hpp" +#include "widgets/propertyFields/intField.hpp" +#include "widgets/propertyFields/selectField.hpp" +#include "widgets/propertyFields/textField.hpp" + +class ProjectSettingsPanelProgram : public SettingsPanelBase { +public: + TextField::Ptr titleField; + TextField::Ptr versionField; + FileField::Ptr programIcon; + IntField::Ptr windowSizeX; + IntField::Ptr windowSizeY; + BoolField::Ptr resizeable; + SelectField::Ptr windowStateFlag; + IntField::Ptr targetFPS; + + ProjectSettingsPanelProgram(tgui::TabContainer::Ptr tabContainer); + void setup(Project *project); +}; + +#endif diff --git a/include/editor/childWindows/projectSettingsWindow.hpp b/include/editor/childWindows/projectSettingsWindow.hpp new file mode 100644 index 00000000..7c687060 --- /dev/null +++ b/include/editor/childWindows/projectSettingsWindow.hpp @@ -0,0 +1,20 @@ +#ifndef _RPGPP_PROJECTSETTINGSWINDOW_H +#define _RPGPP_PROJECTSETTINGSWINDOW_H + +#include + +#include "childWindows/popupWindow.hpp" +#include "childWindows/projectSettingsPanel/game.hpp" +#include "childWindows/projectSettingsPanel/program.hpp" + +class ProjectSettingsWindow : public PopupWindow { +private: + std::unique_ptr program; + std::unique_ptr game; + +public: + ProjectSettingsWindow(); + void open() override; +}; + +#endif \ No newline at end of file diff --git a/include/editor/childWindows/settingsPanel/base.hpp b/include/editor/childWindows/settingsPanel/base.hpp index 83615fc6..c38d000c 100644 --- a/include/editor/childWindows/settingsPanel/base.hpp +++ b/include/editor/childWindows/settingsPanel/base.hpp @@ -7,15 +7,14 @@ #include "services/translationService.hpp" class SettingsPanelBase { - protected: +protected: tgui::Panel::Ptr panel; - public: +public: SettingsPanelBase(tgui::TabContainer::Ptr tabContainer, std::string name) { panel = tabContainer->addTab(name); - bindCustomTranslation( - tabContainer, [this, name](tgui::TabContainer::Ptr tabContainer, - TranslationService &ts) { + bindTranslationWithCallback( + tabContainer, [this, name](tgui::TabContainer::Ptr tabContainer, TranslationService &ts) { int idx = tabContainer->getIndex(panel); tabContainer->changeTabText(idx, ts.getKey(name)); }); diff --git a/include/editor/childWindows/settingsPanel/general.hpp b/include/editor/childWindows/settingsPanel/general.hpp index 288162bd..bcb2fcd3 100644 --- a/include/editor/childWindows/settingsPanel/general.hpp +++ b/include/editor/childWindows/settingsPanel/general.hpp @@ -1,10 +1,14 @@ +#include + #include "base.hpp" #ifndef RPGPP_SETTINGSPANEL_GENERAL_H #define RPGPP_SETTINGSPANEL_GENERAL_H class SettingsPanelGeneral : public SettingsPanelBase { - public: - SettingsPanelGeneral(tgui::TabContainer::Ptr tabContainer); + tgui::MessageBox::Ptr promptUserBox; + +public: + explicit SettingsPanelGeneral(tgui::TabContainer::Ptr tabContainer); }; #endif diff --git a/include/editor/childWindows/settingsPanel/hotkeys.hpp b/include/editor/childWindows/settingsPanel/hotkeys.hpp index 8d0c23e7..90e8df3a 100644 --- a/include/editor/childWindows/settingsPanel/hotkeys.hpp +++ b/include/editor/childWindows/settingsPanel/hotkeys.hpp @@ -4,7 +4,7 @@ #define RPGPP_SETTINGSPANEL_HOTKEYS_H class SettingsPanelHotkeys : public SettingsPanelBase { - public: +public: SettingsPanelHotkeys(tgui::TabContainer::Ptr tabContainer); }; diff --git a/include/editor/childWindows/settingsWindow.hpp b/include/editor/childWindows/settingsWindow.hpp index 563ae41a..7b6eea94 100644 --- a/include/editor/childWindows/settingsWindow.hpp +++ b/include/editor/childWindows/settingsWindow.hpp @@ -6,11 +6,11 @@ #include "settingsPanel/hotkeys.hpp" class SettingsWindow : public PopupWindow { - private: +private: std::shared_ptr general; std::shared_ptr hotkeys; - public: +public: SettingsWindow(); }; diff --git a/include/editor/components/frameButton.hpp b/include/editor/components/frameButton.hpp index 456d7503..c7dbf701 100644 --- a/include/editor/components/frameButton.hpp +++ b/include/editor/components/frameButton.hpp @@ -1,29 +1,29 @@ #ifndef RPGPP_FRAMEBUTTON_H #define RPGPP_FRAMEBUTTON_H +#include + #include "TGUI/Signal.hpp" #include "TGUI/Sprite.hpp" #include "TGUI/Widgets/Button.hpp" #include "actor.hpp" -#include class FrameButton : public tgui::Button { - private: +private: int frameIndex; Actor *actor; tgui::Sprite sprite{}; - public: +public: FrameButton(int frameIndex, Actor *actor); typedef std::shared_ptr Ptr; static FrameButton::Ptr create(int frameIndex, Actor *actor); - void draw(tgui::BackendRenderTarget &target, - tgui::RenderStates states) const override; + void draw(tgui::BackendRenderTarget &target, tgui::RenderStates states) const override; void updateSprite(bool reImport = false); // When the frame button is pressed. Optional parameters: frame index tgui::SignalInt onFrameChange = {"OnFrameChange"}; }; -#endif // RPGPP_FRAMEBUTTON_H +#endif // RPGPP_FRAMEBUTTON_H diff --git a/include/editor/components/perfOverlay.hpp b/include/editor/components/perfOverlay.hpp index 26dd8b6f..269337eb 100644 --- a/include/editor/components/perfOverlay.hpp +++ b/include/editor/components/perfOverlay.hpp @@ -3,7 +3,7 @@ #include "raylib.h" class PerformanceOverlay { - public: +public: PerformanceOverlay(); void Update(); @@ -12,7 +12,7 @@ class PerformanceOverlay { void Toggle(); bool IsEnabled() const; - private: +private: bool enabled{false}; static const int SAMPLE_COUNT = 240; diff --git a/include/editor/components/resizableCanvasBox.hpp b/include/editor/components/resizableCanvasBox.hpp index 741b67c1..228b05f9 100644 --- a/include/editor/components/resizableCanvasBox.hpp +++ b/include/editor/components/resizableCanvasBox.hpp @@ -1,23 +1,16 @@ #ifndef RPGPP_RESIZABLECANVASBOX_H #define RPGPP_RESIZABLECANVASBOX_H -#include "raylib.h" #include -enum ResizeDirection { - NONE = 0, - MOVE = 1 << 0, - TOP = 1 << 1, - BOTTOM = 1 << 2, - LEFT = 1 << 3, - RIGHT = 1 << 4 -}; +#include "raylib.h" + +enum ResizeDirection { NONE = 0, MOVE = 1 << 0, TOP = 1 << 1, BOTTOM = 1 << 2, LEFT = 1 << 3, RIGHT = 1 << 4 }; class ResizableCanvasBox { - public: - ResizableCanvasBox(std::string id, float x, float y, float width, - float height, Color color, bool isResizable = true); - ResizableCanvasBox(std::string id, Rectangle rec, Color color, +public: + ResizableCanvasBox(std::string id, float x, float y, float width, float height, Color color, bool isResizable = true); + ResizableCanvasBox(std::string id, Rectangle rec, Color color, bool isResizable = true); void draw(); // @returns true if the box was clicked, false otherwise @@ -26,6 +19,8 @@ class ResizableCanvasBox { // @returns the new rectangle after the mouse is released Rectangle leftMouseReleased(Vector2 mousePos); + Rectangle getRectangle(); + void updatePosition(float x, float y); void updateSize(float width, float height); void updateColor(Color color); @@ -37,7 +32,7 @@ class ResizableCanvasBox { void setMinSize(float size) { minSize = std::max(size, 2.f); } float getMinSize() const { return minSize; } - private: +private: const float RESIZE_MARGIN = 1.f; float minSize = 2.f; bool isResizable = true; diff --git a/include/editor/components/resizableContainer.hpp b/include/editor/components/resizableContainer.hpp index 98609f68..b5f92c48 100644 --- a/include/editor/components/resizableContainer.hpp +++ b/include/editor/components/resizableContainer.hpp @@ -5,16 +5,10 @@ #include "TGUI/Vector2.hpp" #include "TGUI/Widgets/Group.hpp" -enum class ResizeDirection { - MOVE = 0, - LEFT = 1 << 0, - RIGHT = 1 << 1, - TOP = 1 << 2, - BOTTOM = 1 << 3 -}; +enum class ResizeDirection { MOVE = 0, LEFT = 1 << 0, RIGHT = 1 << 1, TOP = 1 << 2, BOTTOM = 1 << 3 }; class ResizableContainer : public tgui::Group { - private: +private: char resizeFlags = 0; int grabberSize = 15; int maxResizeWidth = 0; @@ -29,12 +23,10 @@ class ResizableContainer : public tgui::Group { bool isGrabbing = false; bool cursorModified = false; - bool inEnabledGrabber(ResizeDirection direction, - tgui::Vector2f absolutePos); + bool inEnabledGrabber(ResizeDirection direction, tgui::Vector2f absolutePos); - public: - ResizableContainer(const tgui::Layout2d &size, - const tgui::Layout2d &position); +public: + ResizableContainer(const tgui::Layout2d &size, const tgui::Layout2d &position); void enableResize(ResizeDirection direction); void disableResize(ResizeDirection direction); bool isResizable(ResizeDirection direction); @@ -53,8 +45,7 @@ class ResizableContainer : public tgui::Group { typedef std::shared_ptr Ptr; typedef std::shared_ptr ConstPtr; - static ResizableContainer::Ptr create(const tgui::Layout2d &size, - const tgui::Layout2d &position); + static ResizableContainer::Ptr create(const tgui::Layout2d &size, const tgui::Layout2d &position); static ResizableContainer::Ptr copy(ResizableContainer::ConstPtr widget); bool useExternalMouseEvent = false; @@ -66,8 +57,8 @@ class ResizableContainer : public tgui::Group { tgui::SignalTyped onResize = {"OnResize"}; - protected: +protected: tgui::Widget::Ptr clone() const override; }; -#endif // RPGPP_RESIZABLECONTAINER_H +#endif // RPGPP_RESIZABLECONTAINER_H diff --git a/include/editor/components/tooltip.hpp b/include/editor/components/tooltip.hpp index 161021de..5b57a8f3 100644 --- a/include/editor/components/tooltip.hpp +++ b/include/editor/components/tooltip.hpp @@ -3,7 +3,7 @@ #include "TGUI/Widgets/Label.hpp" class Tooltip : public tgui::Label { - public: +public: Tooltip(const std::string &text); typedef std::shared_ptr Ptr; typedef std::shared_ptr ConstPtr; @@ -11,7 +11,7 @@ class Tooltip : public tgui::Label { static Ptr create(const std::string &text); static Ptr copy(ConstPtr widget); - protected: +protected: tgui::Widget::Ptr clone() const override; }; diff --git a/include/editor/defaultConfig.hpp b/include/editor/defaultConfig.hpp index 4911fd2e..83690626 100644 --- a/include/editor/defaultConfig.hpp +++ b/include/editor/defaultConfig.hpp @@ -1,19 +1,18 @@ -#include "editor.hpp" -#include "raylib.h" -#include "services/hotkeyService.hpp" #include #include #include #include +#include "editor.hpp" +#include "raylib.h" +#include "services/hotkeyService.hpp" + // key-value using ConfigEntry = std::map; // [field] using Config = std::map; -const std::string h(Hotkey hk) { - return std::to_string(HotkeyService::pack(hk)); -} +const std::string h(Hotkey hk) { return std::to_string(HotkeyService::pack(hk)); } const Config BASE_CONFIG = { {"rpgpp", diff --git a/include/editor/editor.hpp b/include/editor/editor.hpp index a29d477f..c8c32509 100644 --- a/include/editor/editor.hpp +++ b/include/editor/editor.hpp @@ -1,23 +1,23 @@ #ifndef _RGPP_EDITOR_H #define _RGPP_EDITOR_H +#include +#include + #include "project.hpp" #include "raylib.h" +#include "services/configurationService.hpp" #include "services/editorGuiService.hpp" #include "services/fileSystemService.hpp" #include "services/hotkeyService.hpp" #include "services/recentProjectService.hpp" #include "services/themeService.hpp" #include "services/translationService.hpp" -#include -#include - -#include "services/configurationService.hpp" #define RPGPP_VERSION 0.1 class Editor { - private: +private: // NOTE: always initialize the configuration service first. // Otherwise, everything gets screwed over. // NOTE: leave this order of fields, @@ -34,7 +34,7 @@ class Editor { HotkeyService hotkeyService; RecentProjectService recentProjectService; - public: +public: Editor(); ~Editor() = default; // The opened project diff --git a/include/editor/fileInitVisitor.hpp b/include/editor/fileInitVisitor.hpp index 036377aa..c0cad4e5 100644 --- a/include/editor/fileInitVisitor.hpp +++ b/include/editor/fileInitVisitor.hpp @@ -21,6 +21,7 @@ class FileInitVisitor { static void actor(NewFileDialog::Ptr dialog); static void prop(NewFileDialog::Ptr dialog); static void dialogue(NewFileDialog::Ptr dialog); + static void interactable(NewFileDialog::Ptr dialog); }; #endif diff --git a/include/editor/fileTabRenderer.hpp b/include/editor/fileTabRenderer.hpp index c7d6f100..91ec5e92 100644 --- a/include/editor/fileTabRenderer.hpp +++ b/include/editor/fileTabRenderer.hpp @@ -3,7 +3,7 @@ #include "TGUI/Renderers/TabsRenderer.hpp" class FileTabRenderer : public tgui::TabsRenderer { - public: +public: using tgui::TabsRenderer::TabsRenderer; }; diff --git a/include/editor/fileViews/actorFileView.hpp b/include/editor/fileViews/actorFileView.hpp index cbc88cee..854649ac 100644 --- a/include/editor/fileViews/actorFileView.hpp +++ b/include/editor/fileViews/actorFileView.hpp @@ -8,12 +8,12 @@ #include "widgets/propertyFields/rectangleField.hpp" class ActorFileView : public FileView { - private: +private: FileField::Ptr tileSetField; RectangleField::Ptr collisionField; ActorView::Ptr actorView; - public: +public: ActorFileView(); FrameEditor::Ptr frameEditor; diff --git a/include/editor/fileViews/codeFileView.hpp b/include/editor/fileViews/codeFileView.hpp deleted file mode 100644 index 96ff8b02..00000000 --- a/include/editor/fileViews/codeFileView.hpp +++ /dev/null @@ -1,15 +0,0 @@ - -#ifndef RPGPP_CODEFILEVIEW_H -#define RPGPP_CODEFILEVIEW_H -#include "fileView.hpp" -#include "views/codeView.hpp" - -class CodeFileView : public FileView { - CodeView::Ptr codeEditor; - - public: - CodeFileView(); - void init(tgui::Group::Ptr layout, VariantWrapper *variant) override; -}; - -#endif // RPGPP_CODEFILEVIEW_H diff --git a/include/editor/fileViews/dialogueFileView.hpp b/include/editor/fileViews/dialogueFileView.hpp index e3ae89e1..11db3adf 100644 --- a/include/editor/fileViews/dialogueFileView.hpp +++ b/include/editor/fileViews/dialogueFileView.hpp @@ -1,34 +1,40 @@ #ifndef _RPGPP_FILEVIEWS_DIALOGUEFILEVIEW_H #define _RPGPP_FILEVIEWS_DIALOGUEFILEVIEW_H +#include +#include + #include "TGUI/Texture.hpp" #include "TGUI/Widgets/Button.hpp" #include "TGUI/Widgets/GrowVerticalLayout.hpp" #include "TGUI/Widgets/Panel.hpp" #include "TGUI/Widgets/ScrollablePanel.hpp" +#include "dialogue.hpp" #include "dialogueBalloon.hpp" #include "fileViews/fileView.hpp" -#include "services/translationService.hpp" -#include -#include +#include "widgets/dialogueEditor.hpp" class DialogueFileView : public FileView { const float DIALOGUE_PANEL_HEIGHT = 200.0f; - private: +private: + Dialogue *dialogue; + tgui::Button::Ptr newLineButton; tgui::ScrollablePanel::Ptr mainPanel; tgui::GrowVerticalLayout::Ptr vertLayout; tgui::Texture noImageTexture; tgui::Texture deleteTexture; std::vector linePanels; + std::vector dialogueBoxes; + std::vector optionPanels; - tgui::Panel::Ptr makeLinePanel(DialogueBin &data, DialogueLine line, - size_t i); + tgui::Panel::Ptr makeLinePanel(DialogueBin &data, DialogueLine line, size_t i); - public: +public: DialogueFileView(); void init(tgui::Group::Ptr layout, VariantWrapper *variant) override; + void initOptionPanel(int lineIndex); }; #endif diff --git a/include/editor/fileViews/emptyView.hpp b/include/editor/fileViews/emptyView.hpp index 4df297ba..e522b062 100644 --- a/include/editor/fileViews/emptyView.hpp +++ b/include/editor/fileViews/emptyView.hpp @@ -5,7 +5,7 @@ #include "variant.hpp" class EmptyFileView : public FileView { - public: +public: EmptyFileView(); void init(tgui::Group::Ptr layout, VariantWrapper *variant) override; }; diff --git a/include/editor/fileViews/fileView.hpp b/include/editor/fileViews/fileView.hpp index 6032707b..f70001ab 100644 --- a/include/editor/fileViews/fileView.hpp +++ b/include/editor/fileViews/fileView.hpp @@ -1,15 +1,16 @@ #ifndef _RPGPP_FILEVIEW_H #define _RPGPP_FILEVIEW_H +#include +#include +#include + #include "TGUI/Widget.hpp" #include "TGUI/Widgets/Group.hpp" #include "actions/action.hpp" #include "variant.hpp" -#include -#include -#include class FileView { - protected: +protected: VariantWrapper *variant; std::vector widgetContainer; std::vector> actions; @@ -19,7 +20,7 @@ class FileView { std::stack> past; std::stack> future; - public: +public: bool fileViewFocused = false; FileView(); diff --git a/include/editor/fileViews/fontFileView.hpp b/include/editor/fileViews/fontFileView.hpp index dd3a4dc8..0c34c2c7 100644 --- a/include/editor/fileViews/fontFileView.hpp +++ b/include/editor/fileViews/fontFileView.hpp @@ -5,11 +5,11 @@ #include "views/fontView.hpp" class FontFileView : public FileView { - public: +public: FontFileView(); void init(tgui::Group::Ptr layout, VariantWrapper *variant) override; - private: +private: FontView::Ptr fontView; }; diff --git a/include/editor/fileViews/imageFileView.hpp b/include/editor/fileViews/imageFileView.hpp index 8ea6dee2..0f900262 100644 --- a/include/editor/fileViews/imageFileView.hpp +++ b/include/editor/fileViews/imageFileView.hpp @@ -6,11 +6,11 @@ #include "views/imageView.hpp" class ImageFileView : public FileView { - public: +public: ImageFileView(); void init(tgui::Group::Ptr layout, VariantWrapper *variant) override; - private: +private: ImageView::Ptr imageView; tgui::Label::Ptr infoLabel; }; diff --git a/include/editor/fileViews/interactableFileView.hpp b/include/editor/fileViews/interactableFileView.hpp new file mode 100644 index 00000000..c0251362 --- /dev/null +++ b/include/editor/fileViews/interactableFileView.hpp @@ -0,0 +1,24 @@ +#ifndef _RPGPP_FILEVIEWS_INTERACTABLEFILEVIEW_H +#define _RPGPP_FILEVIEWS_INTERACTABLEFILEVIEW_H + +#include "fileView.hpp" +#include "variant.hpp" +#include "widgets/propertiesBox.hpp" +#include "widgets/propertyFields/boolField.hpp" +#include "widgets/propertyFields/fileField.hpp" +#include "widgets/propertyFields/textField.hpp" + +class InteractableFileView : public FileView { +private: + static const int RIGHT_PANEL_W = 300; + TextField::Ptr nameField; + FileField::Ptr scriptField; + BoolField::Ptr onTouchField; + PropertiesBox::Ptr interProps; + +public: + InteractableFileView(); + void init(tgui::Group::Ptr layout, VariantWrapper *variant) override; +}; + +#endif \ No newline at end of file diff --git a/include/editor/fileViews/propFileView.hpp b/include/editor/fileViews/propFileView.hpp index 349f7247..dcf933bf 100644 --- a/include/editor/fileViews/propFileView.hpp +++ b/include/editor/fileViews/propFileView.hpp @@ -3,6 +3,7 @@ #include "fileView.hpp" #include "variant.hpp" +#include "views/propPreview.hpp" #include "views/propView.hpp" #include "widgets/propertyFields/boolField.hpp" #include "widgets/propertyFields/fileField.hpp" @@ -10,14 +11,16 @@ #include "widgets/propertyFields/selectField.hpp" class PropFileView : public FileView { - public: +public: PropFileView(); // ~PropFileView(); void init(tgui::Group::Ptr layout, VariantWrapper *variant) override; - private: +private: void handleModePress(tgui::Vector2f pos); PropView::Ptr propView; + PropPreview::Ptr propPreview; + static const int RIGHT_PANEL_W = 300; BoolField::Ptr hasInteractableField; diff --git a/include/editor/fileViews/roomFileView.hpp b/include/editor/fileViews/roomFileView.hpp index 9af1c032..7977f913 100644 --- a/include/editor/fileViews/roomFileView.hpp +++ b/include/editor/fileViews/roomFileView.hpp @@ -1,6 +1,9 @@ #ifndef _RPGPP_ROOMFILEVIEW_H #define _RPGPP_ROOMFILEVIEW_H +#include +#include + #include "fileView.hpp" #include "roomLayerViewVisitor.hpp" #include "roomViewModesHandler.hpp" @@ -10,11 +13,9 @@ #include "widgets/propertyFields/fileField.hpp" #include "widgets/propertyFields/intField.hpp" #include "widgets/toolbox.hpp" -#include -#include class RoomFileView : public FileView { - private: +private: static const int RIGHT_PANEL_W = 300; static const int LAYER_CHOOSE_H = 32; static const int TOOLBOX_H = LAYER_CHOOSE_H; @@ -33,7 +34,7 @@ class RoomFileView : public FileView { void setRoomTool(ToolboxItem tool); std::vector hotkeyEntries; - public: +public: std::unique_ptr modesHandler; RoomFileView(); ~RoomFileView(); diff --git a/include/editor/fileViews/soundFileView.hpp b/include/editor/fileViews/soundFileView.hpp index 745ad02a..03325712 100644 --- a/include/editor/fileViews/soundFileView.hpp +++ b/include/editor/fileViews/soundFileView.hpp @@ -6,11 +6,11 @@ #include "widgets/soundPlayer.hpp" class SoundFileView : public FileView { - public: +public: SoundFileView(); void init(tgui::Group::Ptr layout, VariantWrapper *variant) override; - private: +private: tgui::Label::Ptr infoLabel; SoundPlayer::Ptr soundPlayer; }; diff --git a/include/editor/fileViews/tilesetFileView.hpp b/include/editor/fileViews/tilesetFileView.hpp index 1d95eba4..4b3012aa 100644 --- a/include/editor/fileViews/tilesetFileView.hpp +++ b/include/editor/fileViews/tilesetFileView.hpp @@ -8,14 +8,14 @@ #include "widgets/propertyFields/intField.hpp" class TileSetFileView : public FileView { - private: +private: static const int RIGHT_PANEL_W = 300; TileSetView::Ptr worldView; IntField::Ptr widthField; IntField::Ptr heightField; FileField::Ptr textureFile; - public: +public: TileSetFileView(); void init(tgui::Group::Ptr layout, VariantWrapper *variant) override; }; diff --git a/include/editor/listHelper.hpp b/include/editor/listHelper.hpp new file mode 100644 index 00000000..0cc8cf59 --- /dev/null +++ b/include/editor/listHelper.hpp @@ -0,0 +1,22 @@ +#ifndef _RPGPP_EDITOR_LISTHELPER_H +#define _RPGPP_EDITOR_LISTHELPER_H + +#include +#include +#include + +template +std::string VecToString(const std::vector &vec) { + std::stringstream stream; + int i = 0; + for (auto &item : vec) { + stream << item; + if (i != (vec.size() - 1)) { + stream << ";"; + } + i++; + } + return stream.str(); +} + +#endif \ No newline at end of file diff --git a/include/editor/project.hpp b/include/editor/project.hpp index 063a1f29..eefec9ed 100644 --- a/include/editor/project.hpp +++ b/include/editor/project.hpp @@ -1,33 +1,43 @@ #ifndef _RPGPP_PROJECT_H #define _RPGPP_PROJECT_H -#include "gamedata.hpp" -#include "services/fileSystemService.hpp" #include #include #include #include #include +#include "gamedata.hpp" +#include "raylib.h" +#include "services/fileSystemService.hpp" + using json = nlohmann::json; +const std::map WindowStateToName = {{0, "windowed"}, + {FLAG_FULLSCREEN_MODE, "exclusive"}, + {FLAG_BORDERLESS_WINDOWED_MODE, "fullscreen"}, + {FLAG_WINDOW_MINIMIZED, "minimized"}, + {FLAG_WINDOW_MAXIMIZED, "maximized"}}; + class Project { - private: +private: std::string projectPath; - std::string projectTitle; + ProjectProgramSettings programSet; + ProjectGameSettings gameSet; - public: +public: + Project() = default; Project(const std::string &path); - static std::string create(const std::string &dirPath, - const std::string &title); - static void openProject(const tgui::String &filePath, - bool forceSwitch = false); + static std::string create(const std::string &dirPath, const std::string &title); + static void openProject(const tgui::String &filePath, bool forceSwitch = false); json toJson(); - std::string &getTitle(); + + ProjectProgramSettings &getProgramSettings(); + ProjectGameSettings &getGameSettings(); + std::string &getBasePath(); std::vector getPaths(EngineFileType fileType); - std::string getResourcePath(EngineFileType fileType, - const std::string &fileName); + std::string getResourcePath(EngineFileType fileType, const std::string &fileName); std::map getInteractableNames(); std::vector getPropsNames(); GameData generateStruct(); diff --git a/include/editor/projectFile.hpp b/include/editor/projectFile.hpp index 12fd0f30..1de8129d 100644 --- a/include/editor/projectFile.hpp +++ b/include/editor/projectFile.hpp @@ -1,26 +1,26 @@ #ifndef _RPGPP_PROJECTFILE_H #define _RPGPP_PROJECTFILE_H +#include + #include "TGUI/Widgets/Group.hpp" #include "fileViews/fileView.hpp" #include "services/fileSystemService.hpp" #include "variant.hpp" -#include class ProjectFile { - private: +private: std::unique_ptr view; std::unique_ptr variant; EngineFileType fileType; std::string filePath; bool isSaveable = true; - public: +public: bool isEmpty = false; ProjectFile(); - ProjectFile(std::unique_ptr view, - std::unique_ptr variant, - EngineFileType fileType, bool isSaveable = true); + ProjectFile(std::unique_ptr view, std::unique_ptr variant, EngineFileType fileType, + bool isSaveable = true); void setFilePath(const std::string &filePath); std::string &getFilePath(); void initUi(tgui::Group::Ptr group); diff --git a/include/editor/projectFileVisitor.hpp b/include/editor/projectFileVisitor.hpp index 6dc3d61c..bace4ade 100644 --- a/include/editor/projectFileVisitor.hpp +++ b/include/editor/projectFileVisitor.hpp @@ -1,23 +1,21 @@ #ifndef _RPGPP_PROJECTFILEVISITOR_H #define _RPGPP_PROJECTFILEVISITOR_H -#include "projectFile.hpp" -#include "services/fileSystemService.hpp" #include #include #include #include +#include "projectFile.hpp" +#include "services/fileSystemService.hpp" + class ProjectFileVisitor { - private: - std::array(const std::string &)>, - FILETYPE_MAX> - funcs; +private: + std::array(const std::string &)>, FILETYPE_MAX> funcs; - public: +public: ProjectFileVisitor(); - std::unique_ptr visit(EngineFileType fileType, - const std::string &path); + std::unique_ptr visit(EngineFileType fileType, const std::string &path); static std::unique_ptr emptyView(const std::string &path); static std::unique_ptr tilesetView(const std::string &path); static std::unique_ptr roomView(const std::string &path); @@ -29,6 +27,7 @@ class ProjectFileVisitor { static std::unique_ptr fontView(const std::string &path); static std::unique_ptr soundView(const std::string &path); static std::unique_ptr musicView(const std::string &path); + static std::unique_ptr interactableView(const std::string &path); }; #endif diff --git a/include/editor/roomLayerViewVisitor.hpp b/include/editor/roomLayerViewVisitor.hpp index 13b42980..fcfa5c66 100644 --- a/include/editor/roomLayerViewVisitor.hpp +++ b/include/editor/roomLayerViewVisitor.hpp @@ -24,6 +24,8 @@ class RoomLayerViewVisitor RoomTool tool; Interactable *inter{nullptr}; Prop *prop{nullptr}; + Actor *actor{nullptr}; + std::string actorName = ""; bool isAvailable = true; Texture2D propTexture{}; Texture2D actorTexture{}; @@ -40,6 +42,8 @@ class RoomLayerViewVisitor tgui::ComboBox::Ptr actorChoose; tgui::EditBox::Ptr actorNameInput; + void updateInteractableChoose(); + ~RoomLayerViewVisitor(); }; diff --git a/include/editor/roomViewModesHandler.hpp b/include/editor/roomViewModesHandler.hpp index 088c053c..8343c98e 100644 --- a/include/editor/roomViewModesHandler.hpp +++ b/include/editor/roomViewModesHandler.hpp @@ -1,12 +1,13 @@ #ifndef _RPGPP_ROOMVIEWMODESHANDLER_H #define _RPGPP_ROOMVIEWMODESHANDLER_H +#include + #include "TGUI/Vector2.hpp" #include "gamedata.hpp" #include "room.hpp" #include "views/roomView.hpp" #include "views/tileSetView.hpp" -#include struct RoomViewState { RoomTool tool; @@ -18,7 +19,7 @@ struct RoomViewState { }; class RoomViewModesHandler { - public: +public: RoomViewState state; std::weak_ptr view; RoomViewModesHandler(); diff --git a/include/editor/saveables/fontWrapper.hpp b/include/editor/saveables/fontWrapper.hpp index d6c3dca7..9b5cba2e 100644 --- a/include/editor/saveables/fontWrapper.hpp +++ b/include/editor/saveables/fontWrapper.hpp @@ -1,14 +1,16 @@ #ifndef _RPGPP_SAVEABLES_FONTWRAPPER_H #define _RPGPP_SAVEABLES_FONTWRAPPER_H -#include "saveable.hpp" +#include + #include #include -#include #include +#include "saveable.hpp" + class FontWrapper : public ISaveable { - public: +public: Font font{}; std::string fontSource; FontWrapper() = default; diff --git a/include/editor/saveables/imageWrapper.hpp b/include/editor/saveables/imageWrapper.hpp index 19a99139..0e62b60c 100644 --- a/include/editor/saveables/imageWrapper.hpp +++ b/include/editor/saveables/imageWrapper.hpp @@ -1,14 +1,16 @@ #ifndef _RPGPP_SAVEABLES_IMAGEWRAPPER_H #define _RPGPP_SAVEABLES_IMAGEWRAPPER_H -#include "saveable.hpp" +#include + #include #include -#include #include +#include "saveable.hpp" + class ImageWrapper : public ISaveable { - public: +public: Image image{}; std::string source; diff --git a/include/editor/saveables/soundWrapper.hpp b/include/editor/saveables/soundWrapper.hpp index 6215920b..8e30e02d 100644 --- a/include/editor/saveables/soundWrapper.hpp +++ b/include/editor/saveables/soundWrapper.hpp @@ -1,14 +1,16 @@ #ifndef _RPGPP_SAVEABLES_SOUNDWRAPPER_H #define _RPGPP_SAVEABLES_SOUNDWRAPPER_H -#include "saveable.hpp" +#include + #include #include -#include #include +#include "saveable.hpp" + class SoundWrapper : public ISaveable { - public: +public: Music sound{}; std::string source; SoundWrapper() = default; diff --git a/include/editor/screens/guiScreen.hpp b/include/editor/screens/guiScreen.hpp index 2d7d8919..d6e2ddea 100644 --- a/include/editor/screens/guiScreen.hpp +++ b/include/editor/screens/guiScreen.hpp @@ -1,12 +1,13 @@ #ifndef _RPGPP_BASE_GUI_WIDGET_H #define _RPGPP_BASE_GUI_WIDGET_H -#include "TGUI/Widgets/MenuBar.hpp" #include #include +#include "TGUI/Widgets/MenuBar.hpp" + class UIScreen { - public: +public: virtual ~UIScreen() = default; UIScreen() = default; diff --git a/include/editor/screens/projectScreen.hpp b/include/editor/screens/projectScreen.hpp index 41e97c7b..d879de47 100644 --- a/include/editor/screens/projectScreen.hpp +++ b/include/editor/screens/projectScreen.hpp @@ -1,6 +1,8 @@ #ifndef _RPGPP_SCREENS_PROJECT_SCREEN_H #define _RPGPP_SCREENS_PROJECT_SCREEN_H +#include + #include "TGUI/Widgets/ContextMenu.hpp" #include "TGUI/Widgets/Group.hpp" #include "TGUI/Widgets/GrowVerticalLayout.hpp" @@ -13,11 +15,10 @@ #include "services/fileSystemService.hpp" #include "services/translationService.hpp" #include "widgets/fileTab.hpp" -#include namespace screens { class ProjectScreen : public UIScreen { - private: +private: static const int TOOLBAR_H = 54; static const int FILETABS_H = 32; @@ -49,13 +50,13 @@ class ProjectScreen : public UIScreen { tgui::String focusedFile; - private: +private: void switchView(tgui::String id); void clearView(); tgui::Group::Ptr createToolBar(); ResizableContainer::Ptr createResourcesList(); - public: +public: void addFileView(EngineFileType fileType, const std::string &path); void addResourceButtons(EngineFileType fileType); void mouseMove(int x, int y) override; @@ -68,5 +69,5 @@ class ProjectScreen : public UIScreen { tgui::Group::Ptr toolBar; }; -} // namespace screens +} // namespace screens #endif diff --git a/include/editor/screens/welcomeScreen.hpp b/include/editor/screens/welcomeScreen.hpp index 7fc251cb..b47220b4 100644 --- a/include/editor/screens/welcomeScreen.hpp +++ b/include/editor/screens/welcomeScreen.hpp @@ -7,12 +7,12 @@ namespace screens { class WelcomeScreen : public UIScreen { - private: +private: NewProjectWindow::Ptr newProjectDialog; - public: +public: void initItems(tgui::Group::Ptr layout) override; const std::string getNameOfScreen() override { return "Welcome"; } }; -} // namespace screens +} // namespace screens #endif diff --git a/include/editor/services/childWindowSubService.hpp b/include/editor/services/childWindowSubService.hpp index 18a9b58a..81b4cf8c 100644 --- a/include/editor/services/childWindowSubService.hpp +++ b/include/editor/services/childWindowSubService.hpp @@ -1,18 +1,20 @@ #ifndef RPGPP_CHILDWINDOWSERVICE_H #define RPGPP_CHILDWINDOWSERVICE_H -#include "childWindows/popupWindow.hpp" #include #include +#include "childWindows/popupWindow.hpp" + class ChildWindowSubService { - private: +private: std::map> childWindows = {}; - public: +public: ChildWindowSubService(); void createWindows(); void openWindow(const std::string &windowName); void resetAndOpen(const std::string windowName); + PopupWindow *getWindow(const std::string &windowName); }; #endif /* RPGPP_CHILDWINDOWSERVICE_H */ diff --git a/include/editor/services/configurationService.hpp b/include/editor/services/configurationService.hpp index 27a5eedc..5c9135c0 100644 --- a/include/editor/services/configurationService.hpp +++ b/include/editor/services/configurationService.hpp @@ -7,21 +7,19 @@ constexpr auto GENERAL_CONF_FIELD = "rpgpp"; #define RPGPP_CONFIG_FILE "rpgpp.ini" class ConfigurationService { - private: +private: std::unique_ptr iniFile; mINI::INIStructure iniStructure; void regenerate(); - public: +public: ConfigurationService(); mINI::INIMap> getField(const std::string &field); std::string getStringValue(const std::string &key); - std::string getStringValue(const std::string &field, - const std::string &key); + std::string getStringValue(const std::string &field, const std::string &key); void setStringValue(const std::string &key, const std::string &value); - void setStringValue(const std::string &field, const std::string &key, - const std::string &value); + void setStringValue(const std::string &field, const std::string &key, const std::string &value); void saveConfiguration(); }; -#endif // RPGPP_CONFIGURATIONSERVICE_H +#endif // RPGPP_CONFIGURATIONSERVICE_H diff --git a/include/editor/services/editorGuiService.hpp b/include/editor/services/editorGuiService.hpp index ecd8c859..7d67c5fa 100644 --- a/include/editor/services/editorGuiService.hpp +++ b/include/editor/services/editorGuiService.hpp @@ -1,6 +1,10 @@ #ifndef _RGPP_EDITOR_GUI_CONTAINER_H #define _RGPP_EDITOR_GUI_CONTAINER_H +#include +#include +#include + #include "TGUI/Backend/raylib.hpp" #include "TGUI/Widget.hpp" #include "TGUI/Widgets/Group.hpp" @@ -11,14 +15,11 @@ #include "screens/guiScreen.hpp" #include "services/childWindowSubService.hpp" #include "updatable.hpp" -#include -#include -#include constexpr auto RPGPP_EXECUTABLE_LOGO = "resources/app-icon.png"; constexpr int ACTION_BUTTON_SIZE = 16; class EditorGuiService { - private: +private: std::vector> updatableWidgets; std::unique_ptr childWindowService; PerformanceOverlay perfOverlay; @@ -29,7 +30,7 @@ class EditorGuiService { std::weak_ptr screenContainer{}; - public: +public: bool isResettingUI = false; EditorGuiService(); ~EditorGuiService() = default; diff --git a/include/editor/services/fileSystemService.hpp b/include/editor/services/fileSystemService.hpp index 458b7624..bb98a5fa 100644 --- a/include/editor/services/fileSystemService.hpp +++ b/include/editor/services/fileSystemService.hpp @@ -1,15 +1,16 @@ #ifndef _RPGPP_FILESYSTEMSERVICE_H #define _RPGPP_FILESYSTEMSERVICE_H -#include "TGUI/String.hpp" -#include "variant.hpp" #include #include #include #include #include -#define FILETYPE_MAX 11 +#include "TGUI/String.hpp" +#include "variant.hpp" + +#define FILETYPE_MAX 12 enum class EngineFileType { FILE_TILESET, @@ -22,21 +23,25 @@ enum class EngineFileType { FILE_SOUND, FILE_MUSIC, FILE_PROP, + FILE_INTERACTABLE, FILE_EMPTY, }; class FileSystemService { - private: +private: std::array typeNames; + std::array, FILETYPE_MAX> typeExtensions; std::string editorBaseDir; - public: +public: FileSystemService(); void unload(); void promptNewProject(); void promptOpenProject(); std::string &getTypeName(EngineFileType fileType); std::array &getTypeNames(); + std::vector &getTypeExtensions(EngineFileType type); + std::array, FILETYPE_MAX> &getTypeExtensions(); const std::string &getEditorBaseDir(); std::string getResourcePath(const std::string &path); void openFileInDefaultApp(std::string &path); diff --git a/include/editor/services/hotkeyService.hpp b/include/editor/services/hotkeyService.hpp index 10cc1fe7..a6831f15 100644 --- a/include/editor/services/hotkeyService.hpp +++ b/include/editor/services/hotkeyService.hpp @@ -1,10 +1,11 @@ -#include "ini.h" -#include "raylib.h" #include #include #include +#include "ini.h" +#include "raylib.h" + #ifndef RPGPP_HOTKEYSERVICE_H #define RPGPP_HOTKEYSERVICE_H @@ -39,16 +40,14 @@ struct Hotkey { }; using HotkeyMap = std::unordered_map; class HotkeyService { - private: - std::map>> - hotkeysCb; +private: + std::map>> hotkeysCb; void write(const std::string &keyId, const std::string &keyStr); HotkeyMap hotkeyMap; - public: +public: HotkeyService(); - std::string registerHotkeyCallback(const std::string &keyId, - std::function cb); + std::string registerHotkeyCallback(const std::string &keyId, std::function cb); void unregisterHotkeyCallback(const std::string &uniqueHkCbId); void addHotkey(const std::string &keyId, const Hotkey &keys); void removeHotkey(const std::string &keyId); diff --git a/include/editor/services/recentProjectService.hpp b/include/editor/services/recentProjectService.hpp index c8f0e691..1b57933a 100644 --- a/include/editor/services/recentProjectService.hpp +++ b/include/editor/services/recentProjectService.hpp @@ -8,16 +8,16 @@ #define RPGPP_RECENT_FILE ".rpgpp_recent_project" class RecentProjectService { - private: +private: int limit = 10; std::deque recentProjects; std::filesystem::path path; void save(); - public: +public: RecentProjectService(); void enqueue(const std::string &projectPath); const std::deque &getRecentProjects() const; }; -#endif // RPGPP_RECENTPROJECTSERVICE_H +#endif // RPGPP_RECENTPROJECTSERVICE_H diff --git a/include/editor/services/themeService.hpp b/include/editor/services/themeService.hpp index 975c9cab..19e33e5b 100644 --- a/include/editor/services/themeService.hpp +++ b/include/editor/services/themeService.hpp @@ -1,8 +1,9 @@ -#include "TGUI/Loading/Theme.hpp" #include #include #include +#include "TGUI/Loading/Theme.hpp" + #ifndef RPGPP_THEMESERVICE_H #define RPGPP_THEMESERVICE_H @@ -12,7 +13,7 @@ constexpr const char *THEME_DIR = "themes"; constexpr const char *DEFAULT_THEME = "Dark"; class ThemeService { - public: +public: ThemeService(Editor *editor_ptr); std::string current_theme_name = DEFAULT_THEME; std::shared_ptr current_theme; diff --git a/include/editor/services/translationService.hpp b/include/editor/services/translationService.hpp index f7a50306..4927fecd 100644 --- a/include/editor/services/translationService.hpp +++ b/include/editor/services/translationService.hpp @@ -21,10 +21,10 @@ constexpr auto DEFAULT_LANGUAGE = "en_us"; // Placeholders are defined with two curly brackets (like `{{test}}`) // and can be replaced using `.replace("test", "value")` class TranslatedString { - private: +private: std::string value; - public: +public: TranslatedString(const std::string &value) : value(value) {} TranslatedString replace(const std::string &k, const std::string &v) { std::string finder = "{{" + k + "}}"; @@ -39,10 +39,9 @@ class TranslatedString { }; class TranslationService { - public: +public: using ListenerID = size_t; - using Callback = std::function; + using Callback = std::function; TranslationService(Editor *editor_ptr); TranslatedString getKey(const std::string &key); void setLanguage(const std::string &language); @@ -53,10 +52,8 @@ class TranslationService { void purgeDeadListeners(); std::map langKeyToName = {}; - private: - std::map>, - std::less<>> - translations = {}; +private: + std::map>, std::less<>> translations = {}; std::map translationFiles = {}; std::string current_language = DEFAULT_LANGUAGE; std::unordered_map listeners; diff --git a/include/editor/syntaxHighlighter.hpp b/include/editor/syntaxHighlighter.hpp index 3d795db4..65772c63 100644 --- a/include/editor/syntaxHighlighter.hpp +++ b/include/editor/syntaxHighlighter.hpp @@ -12,7 +12,7 @@ namespace EditorHighlighting { struct HighlighterStruct { - public: +public: std::string type; uint32_t start; uint32_t end; @@ -20,7 +20,7 @@ struct HighlighterStruct { }; struct TextStyling { - public: +public: tgui::Color color; tgui::TextStyle textStyle; }; @@ -32,6 +32,6 @@ struct TextPiece { std::size_t nodeEnd; }; -} // namespace EditorHighlighting +} // namespace EditorHighlighting #endif /* RPGPP_SYNTAX_HIGHLIGHTER */ diff --git a/include/editor/updatable.hpp b/include/editor/updatable.hpp index f1b44819..fece970f 100644 --- a/include/editor/updatable.hpp +++ b/include/editor/updatable.hpp @@ -2,7 +2,7 @@ #define _RPGPP_UPDATABLE_H class IUpdatable { - public: +public: virtual ~IUpdatable() = default; virtual void update() = 0; diff --git a/include/editor/variant.hpp b/include/editor/variant.hpp index 573fbfca..0f223a6c 100644 --- a/include/editor/variant.hpp +++ b/include/editor/variant.hpp @@ -1,25 +1,26 @@ #ifndef _RPGPP_VARIANT_H #define _RPGPP_VARIANT_H -#include "saveable.hpp" #include +#include "saveable.hpp" + class VariantWrapper { - public: +public: VariantWrapper() {}; virtual ~VariantWrapper() {}; virtual ISaveable *toSaveable() = 0; }; class SaveableVariant { - public: +public: std::unique_ptr data; }; -template class Variant : public VariantWrapper { - public: - static_assert(std::is_base_of::value, - "The template is not the base of ISaveable"); +template +class Variant : public VariantWrapper { +public: + static_assert(std::is_base_of::value, "The template is not the base of ISaveable"); std::unique_ptr data; Variant() = default; @@ -32,7 +33,8 @@ template class Variant : public VariantWrapper { ISaveable *toSaveable() { return dynamic_cast(data.get()); } }; -template ISaveable *toSaveable(Variant *variant) { +template +ISaveable *toSaveable(Variant *variant) { return dynamic_cast(variant->data.get()); } diff --git a/include/editor/views/actorView.hpp b/include/editor/views/actorView.hpp index fb9c348e..19933fe1 100644 --- a/include/editor/views/actorView.hpp +++ b/include/editor/views/actorView.hpp @@ -1,24 +1,25 @@ #ifndef RPGPP_ACTORVIEW_H #define RPGPP_ACTORVIEW_H +#include + #include "actor.hpp" #include "components/resizableCanvasBox.hpp" #include "raylib.h" #include "views/worldView.hpp" -#include constexpr float DEFAULT_ANIMATION_SPEED{2.0f}; class ActorFileView; class ActorView : public WorldView { - private: +private: std::unique_ptr collisionBox; std::unique_ptr atlasBox; float animationCurrentDuration{0.0f}; ActorFileView *actorFileView; - public: +public: ActorView(ActorFileView *actorFileView); Actor *actor{nullptr}; diff --git a/include/editor/views/codeView.hpp b/include/editor/views/codeView.hpp deleted file mode 100644 index 8aa88a5c..00000000 --- a/include/editor/views/codeView.hpp +++ /dev/null @@ -1,34 +0,0 @@ -#ifndef _RPGPP_CODEVIEW_H -#define _RPGPP_CODEVIEW_H - -#include "scriptFile.h" -#include "tree_sitter/api.h" -#include "views/worldView.hpp" -#include -#include - -struct HighlightInformation {}; - -class CodeView : public WorldView { - - private: - ScriptFile *scriptFile; - TSTree *tsTree; - - public: - CodeView(); - CodeView(ScriptFile *scriptFile); - - typedef std::shared_ptr Ptr; - - static CodeView::Ptr create(ScriptFile *scriptFile); - static CodeView::Ptr create(); - - void setCode(ScriptFile *scriptFile); - void mouseMoved(tgui::Vector2f pos) override; - - void drawCanvas() override; - void doTree(TSTreeCursor cursor, TSNode node); -}; - -#endif /* _RPGPP_CODEVIEW_H */ diff --git a/include/editor/views/fontView.hpp b/include/editor/views/fontView.hpp index 8e0219e0..31c4b8b6 100644 --- a/include/editor/views/fontView.hpp +++ b/include/editor/views/fontView.hpp @@ -1,12 +1,13 @@ #ifndef _RPGPP_VIEWS_FONTVIEW_H #define _RPGPP_VIEWS_FONTVIEW_H +#include + #include "saveables/fontWrapper.hpp" #include "views/worldView.hpp" -#include class FontView : public WorldView { - public: +public: typedef std::shared_ptr Ptr; FontView(); diff --git a/include/editor/views/imageView.hpp b/include/editor/views/imageView.hpp index 2d06fd1a..77799288 100644 --- a/include/editor/views/imageView.hpp +++ b/include/editor/views/imageView.hpp @@ -1,13 +1,14 @@ #ifndef _RPGPP_VIEWS_IMAGEVIEW_H #define _RPGPP_VIEWS_IMAGEVIEW_H +#include + #include "raylib.h" #include "saveables/imageWrapper.hpp" #include "views/worldView.hpp" -#include class ImageView : public WorldView { - public: +public: typedef std::shared_ptr Ptr; ImageView(); diff --git a/include/editor/views/propPreview.hpp b/include/editor/views/propPreview.hpp new file mode 100644 index 00000000..b75b0972 --- /dev/null +++ b/include/editor/views/propPreview.hpp @@ -0,0 +1,33 @@ +#ifndef _RPGPP_ACTORPREVIEWVIEW_HPP +#define _RPGPP_ACTORPREVIEWVIEW_HPP + +#include + +#include "components/resizableCanvasBox.hpp" +#include "prop.hpp" +#include "views/worldView.hpp" + +class PropFileView; + +class PropPreview : public WorldView { +private: + Prop *prop{nullptr}; + bool isOverBounds{false}; + ResizableCanvasBox *referenceToBox{nullptr}; + +public: + PropPreview(); + + typedef std::shared_ptr Ptr; + + void setProp(Prop *prop); + void setBox(ResizableCanvasBox *box); + + void drawCanvas() override; + void drawOverlay() override; + + static PropPreview::Ptr create(); + static PropPreview::Ptr create(Prop *prop); +}; + +#endif \ No newline at end of file diff --git a/include/editor/views/propView.hpp b/include/editor/views/propView.hpp index f88a4c3a..7bda0721 100644 --- a/include/editor/views/propView.hpp +++ b/include/editor/views/propView.hpp @@ -1,17 +1,19 @@ #ifndef _RPGPP_PROPVIEWER_H #define _RPGPP_PROPVIEWER_H +#include +#include +#include + #include "TGUI/Signal.hpp" #include "components/resizableCanvasBox.hpp" #include "prop.hpp" #include "raylib.h" #include "views/worldView.hpp" -#include -#include enum RectType { ATLAS_RECT, COLLISION_RECT }; class PropView : public WorldView { - public: +public: PropView(); typedef std::shared_ptr Ptr; Prop *p{nullptr}; @@ -29,14 +31,15 @@ class PropView : public WorldView { void mouseMoved(tgui::Vector2f pos) override; void leftMouseReleased(tgui::Vector2f pos) override; + std::optional getAtlasRect(); + void updateAtlasRect(Rectangle r); void updateCollisionRect(Rectangle r); tgui::SignalTyped onUpdatedAtlasRect = {"onUpdatedAtlasRect"}; - tgui::SignalTyped onUpdatedCollisionRect = { - "onUpdatedCollisionRect"}; + tgui::SignalTyped onUpdatedCollisionRect = {"onUpdatedCollisionRect"}; - private: +private: std::list boxes; ResizableCanvasBox *focusedBox = nullptr; }; diff --git a/include/editor/views/roomView.hpp b/include/editor/views/roomView.hpp index 5d22b672..4400d5dd 100644 --- a/include/editor/views/roomView.hpp +++ b/include/editor/views/roomView.hpp @@ -1,6 +1,8 @@ #ifndef _RPGPP_ROOMVIEW_H #define _RPGPP_ROOMVIEW_H +#include + #include "TGUI/Vector2.hpp" #include "TGUI/Widgets/ComboBox.hpp" #include "fileViews/fileView.hpp" @@ -11,14 +13,13 @@ #include "tileSetView.hpp" #include "tilemap.hpp" #include "views/worldView.hpp" -#include class RoomViewModesHandler; class RoomView : public WorldView { friend class RoomViewModesHandler; - private: +private: RoomLayer layer; IVector selectedTile{-1, -1}; bool brushMode = false; @@ -33,7 +34,7 @@ class RoomView : public WorldView { void handleModePress(tgui::Vector2f pos); void handleEditPress(tgui::Vector2f pos); - public: +public: typedef std::shared_ptr Ptr; Room *room{nullptr}; diff --git a/include/editor/views/tileSetView.hpp b/include/editor/views/tileSetView.hpp index 5a9982fa..02ea83dd 100644 --- a/include/editor/views/tileSetView.hpp +++ b/include/editor/views/tileSetView.hpp @@ -1,18 +1,19 @@ #ifndef RPGPP_TILESETTEXTUREVIEWER #define RPGPP_TILESETTEXTUREVIEWER +#include + #include "TGUI/Signal.hpp" #include "gamedata.hpp" #include "tileset.hpp" #include "views/worldView.hpp" -#include class TileSetView : public WorldView { - private: +private: IVector getTileAtMouse(); IVector selectedTile; - public: +public: typedef std::shared_ptr Ptr; tgui::SignalTyped onTileSelected = {"TileSelected"}; @@ -34,4 +35,4 @@ class TileSetView : public WorldView { bool leftMousePressed(tgui::Vector2f pos) override; }; -#endif // RPGPP_TILESETTEXTUREVIEWER +#endif // RPGPP_TILESETTEXTUREVIEWER diff --git a/include/editor/views/worldView.hpp b/include/editor/views/worldView.hpp index 949eaf47..d4186ee5 100644 --- a/include/editor/views/worldView.hpp +++ b/include/editor/views/worldView.hpp @@ -1,16 +1,17 @@ #ifndef _RPGPP_WORLDVIEW_H #define _RPGPP_WORLDVIEW_H +#include + #include "TGUI/Backend/Renderer/Raylib/CanvasRaylib.hpp" #include "TGUI/Vector2.hpp" #include "TGUI/Widget.hpp" #include "constants/room.hpp" #include "raylib.h" #include "updatable.hpp" -#include class WorldView : public tgui::CanvasRaylib, public IUpdatable { - protected: +protected: Camera2D camera; RenderTexture texture; bool mouseMiddleButton = false; @@ -24,7 +25,7 @@ class WorldView : public tgui::CanvasRaylib, public IUpdatable { float cameraMaxZoom = 5; tgui::Vector2f widgetSize{}; - public: +public: typedef std::shared_ptr Ptr; typedef std::shared_ptr ConstPtr; @@ -36,8 +37,7 @@ class WorldView : public tgui::CanvasRaylib, public IUpdatable { void setSize(const tgui::Layout2d &size) override; bool isMouseOnWidget(tgui::Vector2f pos) const override; - void draw(tgui::BackendRenderTarget &target, - tgui::RenderStates states) const override; + void draw(tgui::BackendRenderTarget &target, tgui::RenderStates states) const override; void resetRender(); @@ -57,13 +57,12 @@ class WorldView : public tgui::CanvasRaylib, public IUpdatable { void drawOrigin(); void update() override; - static std::shared_ptr - asUpdatable(const std::shared_ptr &ptr); + static std::shared_ptr asUpdatable(const std::shared_ptr &ptr); void setTool(RoomTool newTool); bool isInView(); - protected: +protected: tgui::Widget::Ptr clone() const override; }; diff --git a/include/editor/widgets/codeEditor.hpp b/include/editor/widgets/codeEditor.hpp deleted file mode 100644 index 7e09a81b..00000000 --- a/include/editor/widgets/codeEditor.hpp +++ /dev/null @@ -1,72 +0,0 @@ - -#ifndef RPGPP_CODEEDITOR_H -#define RPGPP_CODEEDITOR_H -#include "TGUI/String.hpp" -#include "TGUI/Text.hpp" -#include "TGUI/Vector2.hpp" -#include "TGUI/Widgets/TextArea.hpp" -#include "syntaxHighlighter.hpp" -#include "tree_sitter/api.h" -#include -#include -#include -#include -#include -class CodeEditor : public tgui::TextArea { - public: - typedef std::shared_ptr Ptr; - - static Ptr create(); - CodeEditor(); - ~CodeEditor(); - - void draw(tgui::BackendRenderTarget &target, - tgui::RenderStates states) const override; - - void setCode(tgui::String text); - - private: - TSParser *syntaxParser; - TSTree *tsTree{nullptr}; - - // std::vector> highlightTree; - - std::vector highlightVec; - std::vector fuck; - tgui::Text textWhole; - std::list list; - - tgui::Text constructText(const tgui::String &, - tgui::Vector2f position) const; - tgui::Text constructText(const tgui::String &text) const; - tgui::Text constructText(const tgui::String &text, - const tgui::Color &color) const; - - bool canGainFocus() const override; - bool leftMousePressed(tgui::Vector2f pos) override; - void mouseMoved(tgui::Vector2f pos) override; - bool scrolled(float delta, tgui::Vector2f pos, bool touch) override; - void textEntered(char32_t key) override; - void keyPressed(const tgui::Event::KeyEvent &event) override; - - void backspaceKeyPressed(); - - void parseNode(const TSTreeCursor &cursor, const TSNode &node, - std::list &list); - - std::vector - getStructsFromText(const tgui::String &text); - - tgui::Vector2 findCaretPosition(tgui::Vector2f pos) const; - - void updateSelectionTexts(); - void recalculatePositions(); - - void recalculateVisibleLines(); - std::size_t getColumnAt(std::size_t a) const; - std::size_t getLineAt(std::size_t a) const; - - tgui::Vector2f findCharacterPosWhole(std::size_t pos) const; -}; - -#endif // RPGPP_CODEEDITOR_H diff --git a/include/editor/widgets/dialogueEditor.hpp b/include/editor/widgets/dialogueEditor.hpp new file mode 100644 index 00000000..05b2ba8b --- /dev/null +++ b/include/editor/widgets/dialogueEditor.hpp @@ -0,0 +1,53 @@ +#ifndef _RPGPP_DIALOGUEEDITOR_HPP +#define _RPGPP_DIALOGUEEDITOR_HPP + +#include +#include +#include +#include + +#include "TGUI/String.hpp" +#include "TGUI/Widgets/TextArea.hpp" + +struct XMLTagProperties { + std::string propertyName; + std::string propertyValue; +}; + +class DialogueEditor : public tgui::TextArea { +private: + std::size_t formattingSelectionStart; + std::size_t formattingSelectionEnd; + tgui::String selectedText; + +public: + typedef std::shared_ptr Ptr; + DialogueEditor(); + + static DialogueEditor::Ptr create(); + + /** + * Add the specified XML tag to the user's selected text. + * @param tagName The name of the XML tag to add. + */ + void addXmlTag(std::string tagName); + + /** + * Add the specified XML tag with properties to the user's selected text. + * @param tagName The name of the XML tag to add. + * @param properties The properties to add to the XML tag. + */ + void addXmlTagWithProperties(std::string tagName, std::vector properties); + /** + * This sets a text and resets the current selection. + * @param text Text to set. + */ + void setTextAndReset(std::string text); + /** + * This fixes an interesting case with TGUI .w. + */ + void fixSelectionRange(); + bool isTextNonEditable(std::string& tagName); +}; + +#endif /* _RPGPP_DIALOGUEEDITOR_HPP */ diff --git a/include/editor/widgets/fileChooser.hpp b/include/editor/widgets/fileChooser.hpp index fe69e2ef..cce93268 100644 --- a/include/editor/widgets/fileChooser.hpp +++ b/include/editor/widgets/fileChooser.hpp @@ -7,12 +7,12 @@ #include "TGUI/Widgets/EditBox.hpp" class FileChooser : public tgui::SubwidgetContainer { - private: +private: tgui::String chosenPath; bool selectingDirectory = false; static const int PADDING = 4; - public: +public: tgui::EditBox::Ptr chosenPathLabel; tgui::BitmapButton::Ptr iconButton; std::vector>> pathFilters; @@ -32,10 +32,10 @@ class FileChooser : public tgui::SubwidgetContainer { void setSelectingDirectory(bool selectingDirectory); - private: +private: void updateSize(); - protected: +protected: Widget::Ptr clone() const override; }; diff --git a/include/editor/widgets/fileTab.hpp b/include/editor/widgets/fileTab.hpp index cf364ce3..6f559474 100644 --- a/include/editor/widgets/fileTab.hpp +++ b/include/editor/widgets/fileTab.hpp @@ -1,15 +1,16 @@ #ifndef _RPGPP_FILETAB_H #define _RPGPP_FILETAB_H +#include + #include "TGUI/Signal.hpp" #include "TGUI/Widget.hpp" #include "TGUI/Widgets/Tabs.hpp" #include "components/tooltip.hpp" #include "fileTabRenderer.hpp" -#include class FileTab : public tgui::Tabs { - private: +private: bool isHovering = false; bool isHoldingMouse = false; bool isDragging = false; @@ -27,13 +28,11 @@ class FileTab : public tgui::Tabs { bool cursorModified = false; - void renderTab(tgui::BackendRenderTarget &target, - tgui::RenderStates &states, int idx, bool roundedCorners, - float borderWidth, float usableHeight, - tgui::Sprite &close) const; + void renderTab(tgui::BackendRenderTarget &target, tgui::RenderStates &states, int idx, bool roundedCorners, + float borderWidth, float usableHeight, tgui::Sprite &close) const; void closeAndOpenNextTab(std::size_t idx); - public: +public: bool useExternalMouseEvent = false; typedef std::shared_ptr Ptr; typedef std::shared_ptr ConstPtr; @@ -46,8 +45,7 @@ class FileTab : public tgui::Tabs { static FileTab::Ptr copy(FileTab::ConstPtr widget); - void draw(tgui::BackendRenderTarget &target, - tgui::RenderStates states) const override; + void draw(tgui::BackendRenderTarget &target, tgui::RenderStates states) const override; FileTabRenderer *getSharedRenderer() override; @@ -66,7 +64,7 @@ class FileTab : public tgui::Tabs { size_t addFileTab(const std::string &path, const std::string &fileName); void closeCurrentTab(); - protected: +protected: Widget::Ptr clone() const override; }; diff --git a/include/editor/widgets/frameEditor.hpp b/include/editor/widgets/frameEditor.hpp index 5ce7568f..31885fa6 100644 --- a/include/editor/widgets/frameEditor.hpp +++ b/include/editor/widgets/frameEditor.hpp @@ -1,6 +1,9 @@ #ifndef RPGPP_FRAMEEDITOR_H #define RPGPP_FRAMEEDITOR_H +#include +#include + #include "TGUI/SubwidgetContainer.hpp" #include "TGUI/Widget.hpp" #include "TGUI/Widgets/Button.hpp" @@ -11,13 +14,10 @@ #include "TGUI/Widgets/ToggleButton.hpp" #include "components/frameButton.hpp" #include "views/actorView.hpp" -#include -#include class ActorFileView; class FrameEditor : public tgui::ScrollablePanel { - - private: +private: ActorFileView *fileView; ActorView::Ptr actorView; @@ -27,9 +27,8 @@ class FrameEditor : public tgui::ScrollablePanel { tgui::GrowHorizontalLayout::Ptr frameLayout; std::vector frameButtons; - public: - FrameEditor(ActorFileView *fileView, const char *typeName = "FileChooser", - bool initRenderer = true); +public: + FrameEditor(ActorFileView *fileView, const char *typeName = "FileChooser", bool initRenderer = true); typedef std::shared_ptr Ptr; static FrameEditor::Ptr create(ActorFileView *fileView); @@ -43,7 +42,7 @@ class FrameEditor : public tgui::ScrollablePanel { void addFrameButton(int index); - protected: +protected: tgui::Widget::Ptr clone() const override; }; diff --git a/include/editor/widgets/hotkeyModifier.hpp b/include/editor/widgets/hotkeyModifier.hpp index 6a7ca958..ddbc3d64 100644 --- a/include/editor/widgets/hotkeyModifier.hpp +++ b/include/editor/widgets/hotkeyModifier.hpp @@ -13,29 +13,28 @@ enum State { DEFAULT, START_EDITING, IS_EDITING }; using tguiKey = tgui::Event::KeyboardKey; class HotkeyModifier : public tgui::SubwidgetContainer { - private: +private: std::vector keys; Hotkey hk; tgui::Button::Ptr button; State modifingState = DEFAULT; std::string id; - public: +public: typedef std::shared_ptr Ptr; typedef std::shared_ptr ConstPtr; - HotkeyModifier(const char *typeName = "FileChooser", - bool initRenderer = true); + HotkeyModifier(const char *typeName = "FileChooser", bool initRenderer = true); static HotkeyModifier::Ptr create(); static HotkeyModifier::Ptr copy(HotkeyModifier::ConstPtr widget); void keyPressed(const tgui::Event::KeyEvent &event) override; - void setKey(const std::string &id, KeyboardKey key, bool isShift, - bool isCtrl, bool isAlt, bool isSuper, bool override = false); + void setKey(const std::string &id, KeyboardKey key, bool isShift, bool isCtrl, bool isAlt, bool isSuper, + bool override = false); tgui::SignalTyped2 onChange = {"onChange"}; - protected: +protected: Widget::Ptr clone() const override; }; diff --git a/include/editor/widgets/newProjectWindow.hpp b/include/editor/widgets/newProjectWindow.hpp index a9209980..7bf47b8a 100644 --- a/include/editor/widgets/newProjectWindow.hpp +++ b/include/editor/widgets/newProjectWindow.hpp @@ -4,6 +4,7 @@ #include "TGUI/Backend/raylib.hpp" #include "TGUI/String.hpp" #include "TGUI/Widgets/Button.hpp" +#include "TGUI/Widgets/CheckBox.hpp" #include "TGUI/Widgets/ChildWindow.hpp" #include "TGUI/Widgets/EditBox.hpp" #include "TGUI/Widgets/Label.hpp" @@ -12,19 +13,19 @@ // TODO: Segfault happens when editor is closed. This widget could be causing // segfault, specially when it is at least opened once. class NewProjectWindow { - public: +public: tgui::ChildWindow::Ptr window{nullptr}; tgui::EditBox::Ptr titleField; FileChooser::Ptr fileField; tgui::Button::Ptr confirmButton; tgui::Button::Ptr cancelButton; tgui::Label::Ptr fileLabel; + tgui::CheckBox::Ptr makeDirCheck; typedef std::shared_ptr Ptr; typedef std::shared_ptr ConstPtr; - NewProjectWindow(const char *typeName = "NewProjectWindow", - bool initRenderer = true); + NewProjectWindow(const char *typeName = "NewProjectWindow", bool initRenderer = true); static NewProjectWindow::Ptr create(); static NewProjectWindow::Ptr create(const tgui::String &title); @@ -35,11 +36,9 @@ class NewProjectWindow { void updateSize(const tgui::Layout2d &size); void setFieldTitle(const tgui::String &title); void setFileFieldTitle(const tgui::String &title); - void setPathFilters( - std::vector>> - pathFilters); + void setPathFilters(std::vector>> pathFilters); - private: +private: static const int FIELD_H = 24; static const int BUTTON_W = 100; static const int BUTTON_H = 24; diff --git a/include/editor/widgets/propertiesBox.hpp b/include/editor/widgets/propertiesBox.hpp index d930519d..f5850dd8 100644 --- a/include/editor/widgets/propertiesBox.hpp +++ b/include/editor/widgets/propertiesBox.hpp @@ -1,43 +1,46 @@ #ifndef _RPGPP_PROPERTIESBOX_H #define _RPGPP_PROPERTIESBOX_H +#include +#include + #include "TGUI/String.hpp" #include "TGUI/Widget.hpp" +#include "TGUI/Widgets/Button.hpp" #include "TGUI/Widgets/ChildWindow.hpp" #include "TGUI/Widgets/GrowVerticalLayout.hpp" +#include "interactable.hpp" #include "widgets/propertyFields/boolField.hpp" #include "widgets/propertyFields/fileField.hpp" #include "widgets/propertyFields/intField.hpp" +#include "widgets/propertyFields/interPropField.hpp" #include "widgets/propertyFields/rectangleField.hpp" #include "widgets/propertyFields/selectField.hpp" #include "widgets/propertyFields/textField.hpp" -#include -#include class PropertiesBox : public tgui::ChildWindow { - protected: +protected: static const int GAP = 4; + tgui::Button::Ptr newPropButton; tgui::GrowVerticalLayout::Ptr layout; tgui::Widget::Ptr clone() const override; - public: +public: typedef std::shared_ptr Ptr; typedef std::shared_ptr ConstPtr; - PropertiesBox(const char *typeName = "PropertiesBox", - bool initRenderer = true); + Interactable *interactable = nullptr; + + PropertiesBox(const char *typeName = "PropertiesBox", bool initRenderer = true); static PropertiesBox::Ptr create(); static PropertiesBox::Ptr copy(PropertiesBox::ConstPtr widget); - void draw(tgui::BackendRenderTarget &target, - tgui::RenderStates states) const override; + void draw(tgui::BackendRenderTarget &target, tgui::RenderStates states) const override; - void addPropsJson(nlohmann::json &j); - // void addToggleField(const tgui::String &title); - void addIntField(const tgui::String &title, int initialValue, - std::function callback); + void addPropsJson(nlohmann::json &j, bool clear = true, bool editable = false); + void addIntField(const tgui::String &title, int initialValue, std::function callback); void addIntField(IntField::Ptr field); void addFileField(FileField::Ptr field); void addTextField(TextField::Ptr field); @@ -45,8 +48,10 @@ class PropertiesBox : public tgui::ChildWindow { void addRectangleField(RectangleField::Ptr field); void addSelectField(SelectField::Ptr field); void addButton(const tgui::String &title, std::function callback); - tgui::Button::Ptr constructButton(const tgui::String &title, - std::function callback); + void addInterPropField(InterPropField::Ptr field); + void addPropertiesBox(PropertiesBox::Ptr box); + void addWidget(tgui::Widget::Ptr widget); + tgui::Button::Ptr constructButton(const tgui::String &title, std::function callback); }; #endif diff --git a/include/editor/widgets/propertyFields/boolField.hpp b/include/editor/widgets/propertyFields/boolField.hpp index a650df00..9c3e4d5a 100644 --- a/include/editor/widgets/propertyFields/boolField.hpp +++ b/include/editor/widgets/propertyFields/boolField.hpp @@ -6,13 +6,13 @@ #include "TGUI/Widgets/CheckBox.hpp" #include "TGUI/Widgets/Label.hpp" class BoolField : public tgui::SubwidgetContainer { - private: +private: void updateSize(); - protected: +protected: tgui::Widget::Ptr clone() const override; - public: +public: tgui::Label::Ptr label; tgui::CheckBox::Ptr value; diff --git a/include/editor/widgets/propertyFields/fileField.hpp b/include/editor/widgets/propertyFields/fileField.hpp index 925abe9a..ca780999 100644 --- a/include/editor/widgets/propertyFields/fileField.hpp +++ b/include/editor/widgets/propertyFields/fileField.hpp @@ -1,22 +1,23 @@ #ifndef _RPGPP_FILEFIELD_H #define _RPGPP_FILEFIELD_H +#include +#include + #include "TGUI/SubwidgetContainer.hpp" #include "TGUI/Widget.hpp" #include "TGUI/Widgets/Button.hpp" #include "TGUI/Widgets/Label.hpp" -#include -#include class FileField : public tgui::SubwidgetContainer { - private: +private: tgui::String chosenPath; void updateSize(); - protected: +protected: tgui::Widget::Ptr clone() const override; - public: +public: tgui::Label::Ptr label; tgui::Button::Ptr value; std::vector>> pathFilters; @@ -28,8 +29,7 @@ class FileField : public tgui::SubwidgetContainer { FileField(const char *typeName = "FileField", bool initRenderer = true); static FileField::Ptr create(); - static FileField::Ptr create(const tgui::String &label, - const tgui::String &value); + static FileField::Ptr create(const tgui::String &label, const tgui::String &value); static FileField::Ptr copy(FileField::ConstPtr widget); void setValue(const tgui::String &value); diff --git a/include/editor/widgets/propertyFields/intField.hpp b/include/editor/widgets/propertyFields/intField.hpp index 0ffa1212..870bac4a 100644 --- a/include/editor/widgets/propertyFields/intField.hpp +++ b/include/editor/widgets/propertyFields/intField.hpp @@ -1,22 +1,26 @@ #ifndef _RPGPP_INTFIELD_H #define _RPGPP_INTFIELD_H +#include + #include "TGUI/SubwidgetContainer.hpp" #include "TGUI/Widget.hpp" +#include "TGUI/Widgets/BitmapButton.hpp" #include "TGUI/Widgets/Label.hpp" #include "TGUI/Widgets/SpinControl.hpp" -#include class IntField : public tgui::SubwidgetContainer { - private: +private: void updateSize(); - protected: +protected: tgui::Widget::Ptr clone() const override; - public: +public: tgui::Label::Ptr label; tgui::SpinControl::Ptr value; + tgui::BitmapButton::Ptr remove; + bool removable = false; typedef std::shared_ptr Ptr; typedef std::shared_ptr ConstPtr; @@ -27,6 +31,7 @@ class IntField : public tgui::SubwidgetContainer { static IntField::Ptr copy(IntField::ConstPtr widget); void setSize(const tgui::Layout2d &size) override; + void enableRemoving(); }; #endif diff --git a/include/editor/widgets/propertyFields/interPropField.hpp b/include/editor/widgets/propertyFields/interPropField.hpp new file mode 100644 index 00000000..9ee7b908 --- /dev/null +++ b/include/editor/widgets/propertyFields/interPropField.hpp @@ -0,0 +1,34 @@ +#ifndef _RPGPP_INTERPROPFIELD_H +#define _RPGPP_INTERPROPFIELD_H + +#include +#include +#include + +#include "TGUI/Widgets/BitmapButton.hpp" +#include "TGUI/Widgets/Button.hpp" + +class InterPropField : public tgui::SubwidgetContainer { +private: + void updateSize(); + +protected: + tgui::Widget::Ptr clone() const override; + +public: + tgui::Label::Ptr label; + tgui::Button::Ptr value; + tgui::Button::Ptr remove; + + typedef std::shared_ptr Ptr; + typedef std::shared_ptr ConstPtr; + + InterPropField(const char *typeName = "InterPropField", bool initRenderer = true); + + static InterPropField::Ptr create(); + static InterPropField::Ptr copy(InterPropField::ConstPtr widget); + + void setSize(const tgui::Layout2d &size) override; +}; + +#endif \ No newline at end of file diff --git a/include/editor/widgets/propertyFields/listField.hpp b/include/editor/widgets/propertyFields/listField.hpp new file mode 100644 index 00000000..78ae067b --- /dev/null +++ b/include/editor/widgets/propertyFields/listField.hpp @@ -0,0 +1,63 @@ +#ifndef _RPGPP_LISTFIELD_H +#define _RPGPP_LISTFIELD_H + +#include +#include + +#include "TGUI/SubwidgetContainer.hpp" +#include "TGUI/Widget.hpp" +#include "TGUI/Widgets/Button.hpp" +#include "TGUI/Widgets/Label.hpp" +#include "widgets/propertyFields/fieldConfig.hpp" + +template +class ListField : public tgui::SubwidgetContainer { +private: + std::vector items; + + void updateSize() { + label->setPosition({PADDING, 0}); + label->setSize({getSize().x * 0.5f - PADDING, getSize().y}); + value->setPosition({getSize().x * 0.5, 0}); + value->setSize({getSize().x * 0.5f - PADDING, getSize().y}); + } + +public: + tgui::Label::Ptr label; + tgui::Button::Ptr value; + + typedef std::shared_ptr Ptr; + typedef std::shared_ptr ConstPtr; + + ListField(const char *typeName = "ListField", bool initRenderer = true) + : tgui::SubwidgetContainer(typeName, initRenderer) { + label = tgui::Label::create("Label"); + label->setHorizontalAlignment(tgui::HorizontalAlignment::Left); + label->setVerticalAlignment(tgui::VerticalAlignment::Center); + value = tgui::Button::create(); + + m_container->add(label); + m_container->add(value); + + updateSize(); + } + + static ListField::Ptr create() { return std::make_shared(); } + + static ListField::Ptr copy(ListField::ConstPtr widget) { + if (widget) + return std::static_pointer_cast(widget->clone()); + else + return nullptr; + } + + void setSize(const tgui::Layout2d &size) override { + tgui::SubwidgetContainer::setSize(size); + updateSize(); + } + +protected: + Widget::Ptr clone() const override { return std::make_shared(*this); } +}; + +#endif \ No newline at end of file diff --git a/include/editor/widgets/propertyFields/rectangleField.hpp b/include/editor/widgets/propertyFields/rectangleField.hpp index 2da8bbb1..bdeba680 100644 --- a/include/editor/widgets/propertyFields/rectangleField.hpp +++ b/include/editor/widgets/propertyFields/rectangleField.hpp @@ -7,7 +7,7 @@ #include "TGUI/Widgets/SpinControl.hpp" #include "raylib.h" class RectangleField : public tgui::SubwidgetContainer { - private: +private: void updateSize(); tgui::Label::Ptr l_x; tgui::Label::Ptr l_y; @@ -18,10 +18,10 @@ class RectangleField : public tgui::SubwidgetContainer { tgui::SpinControl::Ptr value_width; tgui::SpinControl::Ptr value_height; - protected: +protected: tgui::Widget::Ptr clone() const override; - public: +public: tgui::Label::Ptr label; void setValue(Rectangle value); Rectangle getValue(); @@ -30,8 +30,7 @@ class RectangleField : public tgui::SubwidgetContainer { typedef std::shared_ptr Ptr; typedef std::shared_ptr ConstPtr; - RectangleField(const char *typeName = "RectangleField", - bool initRenderer = true); + RectangleField(const char *typeName = "RectangleField", bool initRenderer = true); static Ptr create(); static Ptr copy(ConstPtr widget); diff --git a/include/editor/widgets/propertyFields/selectField.hpp b/include/editor/widgets/propertyFields/selectField.hpp index c4ff6206..7511b7d7 100644 --- a/include/editor/widgets/propertyFields/selectField.hpp +++ b/include/editor/widgets/propertyFields/selectField.hpp @@ -2,22 +2,23 @@ #ifndef _RPGPP_SELECTFIELD_H #define _RPGPP_SELECTFIELD_H +#include + #include "TGUI/SubwidgetContainer.hpp" #include "TGUI/Widget.hpp" #include "TGUI/Widgets/ComboBox.hpp" #include "TGUI/Widgets/Group.hpp" #include "TGUI/Widgets/Label.hpp" #include "TGUI/Widgets/SpinControl.hpp" -#include class SelectField : public tgui::Group { - private: +private: void updateSize(); - protected: +protected: tgui::Widget::Ptr clone() const override; - public: +public: tgui::Label::Ptr label; tgui::ComboBox::Ptr value; diff --git a/include/editor/widgets/propertyFields/textField.hpp b/include/editor/widgets/propertyFields/textField.hpp index 40c40d8a..d3d68e1d 100644 --- a/include/editor/widgets/propertyFields/textField.hpp +++ b/include/editor/widgets/propertyFields/textField.hpp @@ -5,14 +5,16 @@ #include #include +#include "TGUI/Widgets/BitmapButton.hpp" + class TextField : public tgui::SubwidgetContainer { - private: +private: void updateSize(); - protected: +protected: tgui::Widget::Ptr clone() const override; - public: +public: tgui::Label::Ptr label; tgui::EditBox::Ptr value; diff --git a/include/editor/widgets/soundPlayer.hpp b/include/editor/widgets/soundPlayer.hpp index eac6893f..8d550563 100644 --- a/include/editor/widgets/soundPlayer.hpp +++ b/include/editor/widgets/soundPlayer.hpp @@ -1,6 +1,8 @@ #ifndef _RPGPP_WIDGETS_SOUNDPLAYER_H #define _RPGPP_WIDGETS_SOUNDPLAYER_H +#include + #include "TGUI/SubwidgetContainer.hpp" #include "TGUI/Texture.hpp" #include "TGUI/Widgets/BitmapButton.hpp" @@ -9,10 +11,9 @@ #include "TGUI/Widgets/Slider.hpp" #include "saveables/soundWrapper.hpp" #include "updatable.hpp" -#include class SoundPlayer : public tgui::SubwidgetContainer, public IUpdatable { - public: +public: typedef std::shared_ptr Ptr; tgui::Panel::Ptr panel; @@ -32,7 +33,7 @@ class SoundPlayer : public tgui::SubwidgetContainer, public IUpdatable { void setSound(SoundWrapper *sound); SoundWrapper *getSound(); - private: +private: SoundWrapper *sound; void updateSize(); @@ -43,7 +44,7 @@ class SoundPlayer : public tgui::SubwidgetContainer, public IUpdatable { bool mouseOnSlider = false; bool hasPlayed = false; - protected: +protected: Widget::Ptr clone() const override; }; diff --git a/include/editor/widgets/toolbox.hpp b/include/editor/widgets/toolbox.hpp index b53b83c9..40939472 100644 --- a/include/editor/widgets/toolbox.hpp +++ b/include/editor/widgets/toolbox.hpp @@ -1,5 +1,7 @@ #ifndef _RPGPP_TOOLBOX2_H #define _RPGPP_TOOLBOX2_H +#include + #include "TGUI/Backend/Renderer/BackendRenderTarget.hpp" #include "TGUI/Vector2.hpp" #include "TGUI/Widgets/BitmapButton.hpp" @@ -8,20 +10,22 @@ #include "TGUI/Widgets/ScrollablePanel.hpp" #include "components/tooltip.hpp" #include "editor.hpp" -#include -template struct ToolboxItemIdentifier { +template +struct ToolboxItemIdentifier { std::string group; IdType id; }; -template struct ToolboxItem : ToolboxItemIdentifier { +template +struct ToolboxItem : ToolboxItemIdentifier { std::string text{}; std::string iconResourcePath{}; }; -template class Toolbox : public tgui::ScrollablePanel { - private: +template +class Toolbox : public tgui::ScrollablePanel { +private: std::vector> toolboxItems; float spaceBetweenItems = 4; float itemPadding = 0; @@ -33,7 +37,7 @@ template class Toolbox : public tgui::ScrollablePanel { void resetToolSelection(std::string groupToReset); // void readjustContentSize(); - public: +public: Toolbox(); ~Toolbox(); @@ -52,30 +56,34 @@ template class Toolbox : public tgui::ScrollablePanel { void removeItemById(const Type &id); void selectTool(const ToolboxItem &item); - tgui::SignalTyped &> onItemClicked = { - "OnItemClicked"}; + tgui::SignalTyped &> onItemClicked = {"OnItemClicked"}; - protected: +protected: Widget::Ptr clone() const override; }; -template void Toolbox::setSpaceBetweenItems(float space) { +template +void Toolbox::setSpaceBetweenItems(float space) { spaceBetweenItems = space; } -template float Toolbox::getSpaceBetweenItems() const { +template +float Toolbox::getSpaceBetweenItems() const { return spaceBetweenItems; } -template void Toolbox::setItemPadding(float padding) { +template +void Toolbox::setItemPadding(float padding) { itemPadding = padding; } -template float Toolbox::getItemPadding() const { +template +float Toolbox::getItemPadding() const { return itemPadding; } -template Toolbox::Toolbox() : tgui::ScrollablePanel() { +template +Toolbox::Toolbox() : tgui::ScrollablePanel() { getRenderer()->setPadding({2, 2, 2, 2}); getRenderer()->setBorders({0, 0, 0, 0}); getRenderer()->setRoundedBorderRadius(0); @@ -87,7 +95,8 @@ template Toolbox::Toolbox() : tgui::ScrollablePanel() { this->add(this->container); } -template Toolbox::~Toolbox() { +template +Toolbox::~Toolbox() { for (auto &w : this->container->getWidgets()) { w->setToolTip(nullptr); } @@ -99,16 +108,12 @@ void Toolbox::resetToolSelection(std::string groupToReset) { auto defaultBtn = tgui::Button::create(); for (const auto &widgets : this->container->getWidgets()) { if (auto btn = std::dynamic_pointer_cast(widgets)) { - ToolboxItemIdentifier identifier = - btn->template getUserData>(); + ToolboxItemIdentifier identifier = btn->template getUserData>(); if (groupToReset == identifier.group) { tgui::ButtonRenderer *renderer = btn->getRenderer(); - tgui::ButtonRenderer *defaultRenderer = - defaultBtn->getRenderer(); - renderer->setBackgroundColor( - defaultRenderer->getBackgroundColor()); - renderer->setBackgroundColorHover( - defaultRenderer->getBackgroundColorHover()); + tgui::ButtonRenderer *defaultRenderer = defaultBtn->getRenderer(); + renderer->setBackgroundColor(defaultRenderer->getBackgroundColor()); + renderer->setBackgroundColorHover(defaultRenderer->getBackgroundColorHover()); renderer->setTexture(defaultRenderer->getTexture()); renderer->setTextureHover(defaultRenderer->getTextureHover()); } @@ -116,11 +121,11 @@ void Toolbox::resetToolSelection(std::string groupToReset) { } } -template void Toolbox::selectTool(const ToolboxItem &item) { +template +void Toolbox::selectTool(const ToolboxItem &item) { for (const auto &widgets : this->container->getWidgets()) { if (auto btn = std::dynamic_pointer_cast(widgets)) { - ToolboxItemIdentifier identifier = - btn->template getUserData>(); + ToolboxItemIdentifier identifier = btn->template getUserData>(); if (identifier.id == item.id) { btn->onClick.emit(btn.get(), tgui::Vector2f{1, 1}); return; @@ -131,8 +136,7 @@ template void Toolbox::selectTool(const ToolboxItem &item) { template void Toolbox::addTool(const ToolboxItem &item, int idx) { - tgui::Texture texture( - Editor::instance->getFs().getResourcePath(item.iconResourcePath)); + tgui::Texture texture(Editor::instance->getFs().getResourcePath(item.iconResourcePath)); set toolsInGroup{}; if (toolGroup.find(item.group) != toolGroup.end()) { @@ -167,8 +171,7 @@ void Toolbox::addTool(const ToolboxItem &item, int idx) { resetToolSelection(item.group); tgui::ButtonRenderer *renderer = btn->getRenderer(); renderer->setBackgroundColor(renderer->getBackgroundColorDown()); - renderer->setBackgroundColorHover( - renderer->getBackgroundColorDown()); + renderer->setBackgroundColorHover(renderer->getBackgroundColorDown()); renderer->setTexture(renderer->getTextureDown()); renderer->setTextureHover(renderer->getTextureDown()); } @@ -183,10 +186,10 @@ void Toolbox::addWidget(tgui::Widget::Ptr widget, int idx) { this->container->insert(idx, widget); } -template void Toolbox::removeItemById(const T &id) { +template +void Toolbox::removeItemById(const T &id) { for (const auto &widget : this->container->getWidgets()) { - ToolboxItemIdentifier identifier = - widget->template getUserData>(); + ToolboxItemIdentifier identifier = widget->template getUserData>(); if (identifier.id == id) { this->container->remove(widget); toolGroup[identifier.group].erase(id); @@ -196,7 +199,8 @@ template void Toolbox::removeItemById(const T &id) { // readjustContentSize(); } -template typename Toolbox::Ptr Toolbox::create() { +template +typename Toolbox::Ptr Toolbox::create() { return std::make_shared>(); } @@ -208,7 +212,8 @@ typename Toolbox::Ptr Toolbox::copy(Toolbox::ConstPtr widget) { return nullptr; } -template tgui::Widget::Ptr Toolbox::clone() const { +template +tgui::Widget::Ptr Toolbox::clone() const { return std::make_shared(*this); } diff --git a/include/game.hpp b/include/game.hpp index cac70811..680e86c2 100644 --- a/include/game.hpp +++ b/include/game.hpp @@ -5,19 +5,20 @@ #include "sol/state_view.hpp" class WorldService; +#include +#include + #include "gamedata.hpp" #include "interfaceService.hpp" #include "resourceService.hpp" #include "soundService.hpp" #include "stateService.hpp" #include "worldService.hpp" -#include -#include #define RPGPP_VER "0.1" class Game { - private: +private: static Game *instance_; static std::unique_ptr gameData; static bool usesBin; @@ -28,9 +29,10 @@ class Game { static std::unique_ptr sounds; static std::unique_ptr scripts; - public: +public: Game(); static Game &instance(); + static bool isUsingBin(); static void useBin(const std::string &filePath); static GameData &getBin(); static StateService &getState(); diff --git a/include/gamedata.hpp b/include/gamedata.hpp index d450558a..8913f704 100644 --- a/include/gamedata.hpp +++ b/include/gamedata.hpp @@ -1,10 +1,11 @@ #ifndef _RPGPP_GAMEDATA_H #define _RPGPP_GAMEDATA_H +#include + #include #include #include -#include #include #include @@ -16,13 +17,9 @@ struct IVector { int x; int y; - bool operator==(const IVector &other) const { - return x == other.x && y == other.y; - } + bool operator==(const IVector &other) const { return x == other.x && y == other.y; } - bool operator<(const IVector &other) const { - return x < other.x || (x == other.x && y < other.y); - } + bool operator<(const IVector &other) const { return x < other.x || (x == other.x && y < other.y); } IVector() = default; IVector(int x, int y) { @@ -53,6 +50,8 @@ struct ActorInRoomBin { std::string name; std::string source; IVector tilePos; + std::string intType; + std::vector propsCbor; }; struct TileBin { @@ -93,6 +92,12 @@ struct TileSetBin { int dataSize; }; +struct FontBin { + std::vector data; + int dataSize; + std::string ext; +}; + struct ImageBin { std::vector data; int dataSize; @@ -133,8 +138,30 @@ struct GameBinSettings { std::string playerActor; }; +struct ProjectProgramSettings { + std::string projectTitle; + std::string projectVersion; + IVector windowSize = {640, 480}; + std::string programIconPath = ""; + bool windowResizeableFlag = false; + int targetFPS = 60; + int windowStateFlag = 0; +}; + +struct ProjectGameSettings { + std::string defaultRoomPath; + std::string playerActorPath; + int tileSize = 16; + bool debugDraw = false; + std::vector exportImageScales = {1}; + std::vector exportFontSizes = {13}; +}; + struct GameData { std::string title; + ProjectProgramSettings programSet; + ProjectGameSettings gameSet; + std::map fonts; std::map images; std::map tilesets; std::map interactables; diff --git a/include/imageRect.hpp b/include/imageRect.hpp index 26f0e083..3acff511 100644 --- a/include/imageRect.hpp +++ b/include/imageRect.hpp @@ -1,17 +1,19 @@ #ifndef _RPGPP_IMAGERECT_H #define _RPGPP_IMAGERECT_H -#include "uiElement.hpp" #include + #include +#include "uiElement.hpp" + class ImageRect : public UIElement { - private: +private: Rectangle rect; std::string source; Texture2D texture; - public: +public: ImageRect(); ImageRect(Rectangle rect); void setSource(const std::string &source); diff --git a/include/interactable.hpp b/include/interactable.hpp index cdd24dab..3d65422d 100644 --- a/include/interactable.hpp +++ b/include/interactable.hpp @@ -13,6 +13,8 @@ #include "gamedata.hpp" #include "saveable.hpp" +enum PropType { PROP_INT, PROP_STRING, PROP_BOOLEAN, PROP_DIALOGUE }; + /** Defines an object that is interactable in-game by a player's action */ class Interactable : public ISaveable { private: @@ -40,7 +42,7 @@ class Interactable : public ISaveable { public: /** Empty constructor */ Interactable(); - /** COnstructor using a JSON file. */ + /** Constructor using a JSON file. */ Interactable(const std::string &path); /** Construct from type name */ Interactable(const std::string &type, Vector2 tilePos, int tileSize); @@ -70,10 +72,16 @@ class Interactable : public ISaveable { void setProp(std::string key, std::string value); /** Set properties using a nlohmann::json object. */ void setProps(nlohmann::json j); + /** Add a property based on the chosen property type. */ + void addProp(PropType propType, const std::string &name); + /** Set the source script file path. */ + void setScriptSourcePath(const std::string &newPath); /** Get source script file. */ const std::string &getScriptSourcePath(); /** Get the properties json object. */ nlohmann::json &getProps(); + /** Get a pointer to the properties. */ + nlohmann::json *getPropsPtr(); /** Set the Interactable's display title (shown in Editor) */ void setDisplayTitle(const std::string &newTitle); /** Get the Interactable's display title. */ diff --git a/include/interactablesContainer.hpp b/include/interactablesContainer.hpp index 03b2b502..e530f1e3 100644 --- a/include/interactablesContainer.hpp +++ b/include/interactablesContainer.hpp @@ -1,19 +1,18 @@ #ifndef _RPGPP_INTERACTABLESCONTAINER_H #define _RPGPP_INTERACTABLESCONTAINER_H -#include "baseContainer.hpp" -#include "gamedata.hpp" -#include "interactable.hpp" #include #include #include + +#include "baseContainer.hpp" +#include "gamedata.hpp" +#include "interactable.hpp" using json = nlohmann::json; /** Container of Interactables that is to be used by a [Room](Room.md) */ -class InteractablesContainer - : public BaseContainer> { - - public: +class InteractablesContainer : public BaseContainer> { +public: /** Empty constructor */ InteractablesContainer(); /** Add a new Interactable with tile position and type */ diff --git a/include/interfaceService.hpp b/include/interfaceService.hpp index 6969e0aa..97de8ba8 100644 --- a/include/interfaceService.hpp +++ b/include/interfaceService.hpp @@ -1,16 +1,18 @@ #ifndef _RPGPP_INTERFACESERVICE_H #define _RPGPP_INTERFACESERVICE_H -#include "dialogueBalloon.hpp" -#include "interfaceView.hpp" +#include + #include #include -#include #include +#include "dialogueBalloon.hpp" +#include "interfaceView.hpp" + /** The InterfaceService acts for the User Interface (UI). */ class InterfaceService { - private: +private: /** The loaded font that will be used for the User Interface. */ Font font; bool fpsVisible; @@ -21,7 +23,7 @@ class InterfaceService { /** Available UI Views. */ std::unique_ptr> views; - public: +public: /** Empty constructor. */ InterfaceService(); ~InterfaceService(); diff --git a/include/interfaceView.hpp b/include/interfaceView.hpp index 17703c1e..ac8c8672 100644 --- a/include/interfaceView.hpp +++ b/include/interfaceView.hpp @@ -1,17 +1,19 @@ #ifndef _RPGPP_INTERFACEVIEW_H #define _RPGPP_INTERFACEVIEW_H -#include "uiElement.hpp" -#include #include + +#include #include +#include "uiElement.hpp" + class InterfaceView { - private: +private: Rectangle rect; std::vector> elements; - public: +public: InterfaceView(); explicit InterfaceView(Rectangle rect); void addElement(UIElement *element); diff --git a/include/player.hpp b/include/player.hpp index f075b1a5..b4b97d9a 100644 --- a/include/player.hpp +++ b/include/player.hpp @@ -59,6 +59,8 @@ class Player { void setTilePosition(Vector2 tilePos); /** Get the position of the collision. */ Vector2 getCollisionPos() const; + /** Get the center position of the player's collision. */ + Vector2 getCollisionCenterPos() const; }; #endif diff --git a/include/propsContainer.hpp b/include/propsContainer.hpp index 476a43c7..4448e37a 100644 --- a/include/propsContainer.hpp +++ b/include/propsContainer.hpp @@ -1,12 +1,13 @@ #ifndef _RPGPP_PROPSCONTAINER_H #define _RPGPP_PROPSCONTAINER_H +#include + #include "baseContainer.hpp" #include "prop.hpp" -#include class PropsContainer : public BaseContainer> { - public: +public: PropsContainer() = default; void addProp(Vector2 pos, const std::string &type); Prop *getPropAt(Vector2 pos); diff --git a/include/resourceService.hpp b/include/resourceService.hpp index 387572fc..947f3584 100644 --- a/include/resourceService.hpp +++ b/include/resourceService.hpp @@ -1,20 +1,26 @@ #ifndef _RPGPP_EDITOR_RESOURCESERVICE_H #define _RPGPP_EDITOR_RESOURCESERVICE_H -#include #include + +#include #include class ResourceService { - private: +private: std::map textures; + std::map fonts; - public: +public: ResourceService(); ~ResourceService(); + void init(); void addTextureFromFile(const std::string &filePath); void addTexture(const std::string &id, Texture2D texture); Texture2D getTexture(const std::string &id); + void addFont(const std::string &id, Font font); + void addFontFromFile(const std::string &filePath, int fontSize); + Font getFont(const std::string &id); void unload() const; }; diff --git a/include/room.hpp b/include/room.hpp index e68621e0..6b271f4c 100644 --- a/include/room.hpp +++ b/include/room.hpp @@ -7,13 +7,15 @@ constexpr const char *DEFAULT_PLAYER_PATH = "actors/playerActor.ractor"; class Player; class TileMap; -#include "gamedata.hpp" +#include + #include #include -#include #include #include +#include "gamedata.hpp" + using json = nlohmann::json; #include "actor.hpp" #include "actorContainer.hpp" @@ -28,7 +30,7 @@ using json = nlohmann::json; * interactables, collisions and the TileMap */ class Room : public ISaveable { - private: +private: bool lock; int worldTileSize; /** The camera. */ @@ -51,11 +53,11 @@ class Room : public ISaveable { std::unique_ptr player; void updateCamera(); - public: +public: /** Empty constructor */ Room(); /** Construct a Room from an .rmap file */ - Room(const std::string &fileName, int tileSize = 48); + Room(const std::string &fileName, int tileSize = 48, bool createPlayer = true); /** Construct a Room by using a TileMap pointer */ Room(std::unique_ptr tileMap); /** Construct a Room by using the RoomBin binary structure diff --git a/include/saveable.hpp b/include/saveable.hpp index 950605b2..b5d3688d 100644 --- a/include/saveable.hpp +++ b/include/saveable.hpp @@ -4,7 +4,7 @@ #include class ISaveable { - public: +public: ISaveable() = default; virtual ~ISaveable() = default; virtual nlohmann::json dumpJson() = 0; diff --git a/include/scriptService.hpp b/include/scriptService.hpp index d1377e97..657bacbf 100644 --- a/include/scriptService.hpp +++ b/include/scriptService.hpp @@ -1,16 +1,17 @@ #ifndef _RPGPP_SCRIPTSERVICE_H #define _RPGPP_SCRIPTSERVICE_H -#include "sol/state.hpp" -#include "sol/state_view.hpp" #include #include +#include "sol/state.hpp" +#include "sol/state_view.hpp" + class ScriptService { - private: +private: sol::state state; - public: +public: ScriptService(); sol::state &getState(); void setLua(sol::state_view lua); diff --git a/include/soundService.hpp b/include/soundService.hpp index 9a8bacdc..3f44f4fd 100644 --- a/include/soundService.hpp +++ b/include/soundService.hpp @@ -2,6 +2,7 @@ #define _RPGPP_SOUNDSERVICE_H #include + #include //** The SoundService is responsible for playing sounds and managing the current background music */ @@ -13,7 +14,7 @@ class SoundService { //** The id of the last played music */ std::string lastId; - public: +public: //** Default constructor */ SoundService(); //** Load music with the specified id. */ diff --git a/include/stateService.hpp b/include/stateService.hpp index df845a3b..02652902 100644 --- a/include/stateService.hpp +++ b/include/stateService.hpp @@ -1,22 +1,22 @@ #ifndef _RPGPP_STATESERVICE_H #define _RPGPP_STATESERVICE_H -#include "sol/table.hpp" -#include "sol/types.hpp" #include #include #include +#include "sol/table.hpp" +#include "sol/types.hpp" + /** The StateService is responsible for storing gameplay-related variables * that make up the state of the game. */ -using Value = std::variant; +using Value = std::variant; class StateService { - private: +private: /** A pair of string keys and boolean values. */ std::map gameState; - public: +public: /** Empty constructor */ StateService(); /** Set a property */ diff --git a/include/textArea.hpp b/include/textArea.hpp index e772fc20..dfce7781 100644 --- a/include/textArea.hpp +++ b/include/textArea.hpp @@ -1,17 +1,19 @@ #ifndef _RPGPP_TEXTAREA_H #define _RPGPP_TEXTAREA_H -#include "uiElement.hpp" #include + #include +#include "uiElement.hpp" + class TextArea : public UIElement { - private: +private: Rectangle rect; std::string content; void putChar(int i, Vector2 *charPos, Vector2 *charMeasure) const; - public: +public: TextArea(); TextArea(Rectangle rect); void setText(const std::string &text); diff --git a/include/tile.hpp b/include/tile.hpp index 3969a6f9..a43c9e38 100644 --- a/include/tile.hpp +++ b/include/tile.hpp @@ -1,14 +1,15 @@ #ifndef _RPGPP_TILE_H #define _RPGPP_TILE_H -#include "atlasTile.hpp" #include +#include "atlasTile.hpp" + /** * A tile that may be placed in the world. */ class Tile { - private: +private: /** The Tile's source AtlasTile. */ AtlasTile atlasTile; /** The Tile's World coordinates. */ @@ -16,7 +17,7 @@ class Tile { /** Whether this Tile is placed and will be drawn or not. */ bool placed; - public: +public: Tile(); /** diff --git a/include/uiElement.hpp b/include/uiElement.hpp index e42da743..4467ce56 100644 --- a/include/uiElement.hpp +++ b/include/uiElement.hpp @@ -2,7 +2,7 @@ #define _RPGPP_UIELEMENT_H class UIElement { - public: +public: virtual ~UIElement() = default; UIElement(); diff --git a/include/winapi.hpp b/include/winapi.hpp index 9a9f897c..5c6d455b 100644 --- a/include/winapi.hpp +++ b/include/winapi.hpp @@ -13,5 +13,6 @@ bool WinOpenFileAssociate(std::string operation, std::string file); void WinCreateProc(std::string cmdLine); VsInfo WinVsWhere(std::string path); VsInfo ParseVsWhereData(std::string output); - +bool WinCreateDetachedExecutable(std::string path); +void WinRunWithLog(std::string logName, std::string cmdLine); #endif \ No newline at end of file diff --git a/include/worldService.hpp b/include/worldService.hpp index 3bb2e436..4fa9c9b3 100644 --- a/include/worldService.hpp +++ b/include/worldService.hpp @@ -1,16 +1,17 @@ #ifndef _RPGPP_WORLDSERVICE_H #define _RPGPP_WORLDSERVICE_H -#include "gamedata.hpp" -#include "player.hpp" -#include "room.hpp" #include #include #include +#include "gamedata.hpp" +#include "player.hpp" +#include "room.hpp" + /** The WorldService is responsible for containing and drawing the Room. */ class WorldService { - private: +private: /** The current room in this World. */ std::unique_ptr room; bool lock; @@ -24,7 +25,7 @@ class WorldService { float alpha; bool transitionSecondStage; - public: +public: /** Empty constructor. */ WorldService(); /** Get a reference to the current room. */ diff --git a/resources/defaults/actors/playerActor.ractor b/resources/defaults/actors/playerActor.ractor new file mode 100644 index 00000000..f3c9e1da --- /dev/null +++ b/resources/defaults/actors/playerActor.ractor @@ -0,0 +1 @@ +{"animations":{"down":[[2,0],[3,0]],"down-idle":[[0,0],[1,0]],"left":[[2,2],[3,2]],"left-idle":[[0,2],[1,2]],"right":[[2,3],[3,3]],"right-idle":[[0,3],[1,3]],"up":[[2,1],[3,1]],"up-idle":[[0,1],[1,1]]},"collision":[6,24,36,24],"tileset":"tilesets/actorTiles.rtiles"} \ No newline at end of file diff --git a/resources/defaults/dialogues/welcome.rdiag b/resources/defaults/dialogues/welcome.rdiag new file mode 100644 index 00000000..3ccb9beb --- /dev/null +++ b/resources/defaults/dialogues/welcome.rdiag @@ -0,0 +1 @@ +{"diag":[["Introductor","Welcome to RPG++!","0",""]]} \ No newline at end of file diff --git a/resources/defaults/fonts/LanaPixel.ttf b/resources/defaults/fonts/LanaPixel.ttf new file mode 100644 index 00000000..33cad50b Binary files /dev/null and b/resources/defaults/fonts/LanaPixel.ttf differ diff --git a/resources/defaults/images/Hills.png b/resources/defaults/images/Hills.png new file mode 100644 index 00000000..3818f93b Binary files /dev/null and b/resources/defaults/images/Hills.png differ diff --git a/resources/defaults/images/character.png b/resources/defaults/images/character.png new file mode 100644 index 00000000..a6882014 Binary files /dev/null and b/resources/defaults/images/character.png differ diff --git a/resources/defaults/images/prop.png b/resources/defaults/images/prop.png new file mode 100644 index 00000000..e9c40ff3 Binary files /dev/null and b/resources/defaults/images/prop.png differ diff --git a/resources/defaults/images/ui-npatch.png b/resources/defaults/images/ui-npatch.png new file mode 100644 index 00000000..70a338f0 Binary files /dev/null and b/resources/defaults/images/ui-npatch.png differ diff --git a/resources/defaults/maps/map.rmap b/resources/defaults/maps/map.rmap new file mode 100644 index 00000000..c2674f64 --- /dev/null +++ b/resources/defaults/maps/map.rmap @@ -0,0 +1 @@ +{"actors":{},"collision":[],"height":20,"interactables":{},"map":[[[-1,-1],[-1,-1],[-1,-1],[-1,-1],[-1,-1],[-1,-1],[0,0],[1,0],[1,0],[1,0],[1,0],[1,0],[1,0],[2,0],[-1,-1],[-1,-1],[-1,-1],[-1,-1],[-1,-1],[-1,-1]],[[-1,-1],[-1,-1],[-1,-1],[-1,-1],[-1,-1],[-1,-1],[0,1],[1,1],[1,1],[1,1],[1,1],[1,1],[1,1],[2,1],[-1,-1],[-1,-1],[-1,-1],[-1,-1],[-1,-1],[-1,-1]],[[-1,-1],[-1,-1],[-1,-1],[-1,-1],[-1,-1],[-1,-1],[0,1],[1,1],[1,1],[1,1],[1,1],[1,1],[1,1],[2,1],[-1,-1],[-1,-1],[-1,-1],[-1,-1],[-1,-1],[-1,-1]],[[-1,-1],[-1,-1],[-1,-1],[-1,-1],[-1,-1],[-1,-1],[0,2],[1,2],[1,2],[1,2],[1,2],[1,2],[1,2],[2,2],[-1,-1],[-1,-1],[-1,-1],[-1,-1],[-1,-1],[-1,-1]],[[-1,-1],[-1,-1],[-1,-1],[-1,-1],[-1,-1],[-1,-1],[-1,-1],[-1,-1],[-1,-1],[-1,-1],[-1,-1],[-1,-1],[-1,-1],[-1,-1],[-1,-1],[-1,-1],[-1,-1],[-1,-1],[-1,-1],[-1,-1]],[[-1,-1],[-1,-1],[-1,-1],[-1,-1],[-1,-1],[-1,-1],[-1,-1],[-1,-1],[-1,-1],[-1,-1],[-1,-1],[-1,-1],[-1,-1],[-1,-1],[-1,-1],[-1,-1],[-1,-1],[-1,-1],[-1,-1],[-1,-1]],[[-1,-1],[-1,-1],[-1,-1],[-1,-1],[-1,-1],[-1,-1],[-1,-1],[-1,-1],[-1,-1],[-1,-1],[-1,-1],[-1,-1],[-1,-1],[-1,-1],[-1,-1],[-1,-1],[-1,-1],[-1,-1],[-1,-1],[-1,-1]],[[-1,-1],[-1,-1],[-1,-1],[-1,-1],[-1,-1],[-1,-1],[-1,-1],[-1,-1],[-1,-1],[-1,-1],[-1,-1],[-1,-1],[-1,-1],[-1,-1],[-1,-1],[-1,-1],[-1,-1],[-1,-1],[-1,-1],[-1,-1]],[[-1,-1],[-1,-1],[-1,-1],[-1,-1],[-1,-1],[-1,-1],[-1,-1],[-1,-1],[-1,-1],[-1,-1],[-1,-1],[-1,-1],[-1,-1],[-1,-1],[-1,-1],[-1,-1],[-1,-1],[-1,-1],[-1,-1],[-1,-1]],[[-1,-1],[-1,-1],[-1,-1],[-1,-1],[-1,-1],[-1,-1],[-1,-1],[-1,-1],[-1,-1],[-1,-1],[-1,-1],[-1,-1],[-1,-1],[-1,-1],[-1,-1],[-1,-1],[-1,-1],[-1,-1],[-1,-1],[-1,-1]],[[-1,-1],[-1,-1],[-1,-1],[-1,-1],[-1,-1],[-1,-1],[-1,-1],[-1,-1],[-1,-1],[-1,-1],[-1,-1],[-1,-1],[-1,-1],[-1,-1],[-1,-1],[-1,-1],[-1,-1],[-1,-1],[-1,-1],[-1,-1]],[[-1,-1],[-1,-1],[-1,-1],[-1,-1],[-1,-1],[-1,-1],[-1,-1],[-1,-1],[-1,-1],[-1,-1],[-1,-1],[-1,-1],[-1,-1],[-1,-1],[-1,-1],[-1,-1],[-1,-1],[-1,-1],[-1,-1],[-1,-1]],[[-1,-1],[-1,-1],[-1,-1],[-1,-1],[-1,-1],[-1,-1],[-1,-1],[-1,-1],[-1,-1],[-1,-1],[-1,-1],[-1,-1],[-1,-1],[-1,-1],[-1,-1],[-1,-1],[-1,-1],[-1,-1],[-1,-1],[-1,-1]],[[-1,-1],[-1,-1],[-1,-1],[-1,-1],[-1,-1],[-1,-1],[-1,-1],[-1,-1],[-1,-1],[-1,-1],[-1,-1],[-1,-1],[-1,-1],[-1,-1],[-1,-1],[-1,-1],[-1,-1],[-1,-1],[-1,-1],[-1,-1]],[[-1,-1],[-1,-1],[-1,-1],[-1,-1],[-1,-1],[-1,-1],[-1,-1],[-1,-1],[-1,-1],[-1,-1],[-1,-1],[-1,-1],[-1,-1],[-1,-1],[-1,-1],[-1,-1],[-1,-1],[-1,-1],[-1,-1],[-1,-1]],[[-1,-1],[-1,-1],[-1,-1],[-1,-1],[-1,-1],[-1,-1],[-1,-1],[-1,-1],[-1,-1],[-1,-1],[-1,-1],[-1,-1],[-1,-1],[-1,-1],[-1,-1],[-1,-1],[-1,-1],[-1,-1],[-1,-1],[-1,-1]],[[-1,-1],[-1,-1],[-1,-1],[-1,-1],[-1,-1],[-1,-1],[-1,-1],[-1,-1],[-1,-1],[-1,-1],[-1,-1],[-1,-1],[-1,-1],[-1,-1],[-1,-1],[-1,-1],[-1,-1],[-1,-1],[-1,-1],[-1,-1]],[[-1,-1],[-1,-1],[-1,-1],[-1,-1],[-1,-1],[-1,-1],[-1,-1],[-1,-1],[-1,-1],[-1,-1],[-1,-1],[-1,-1],[-1,-1],[-1,-1],[-1,-1],[-1,-1],[-1,-1],[-1,-1],[-1,-1],[-1,-1]],[[-1,-1],[-1,-1],[-1,-1],[-1,-1],[-1,-1],[-1,-1],[-1,-1],[-1,-1],[-1,-1],[-1,-1],[-1,-1],[-1,-1],[-1,-1],[-1,-1],[-1,-1],[-1,-1],[-1,-1],[-1,-1],[-1,-1],[-1,-1]],[[-1,-1],[-1,-1],[-1,-1],[-1,-1],[-1,-1],[-1,-1],[-1,-1],[-1,-1],[-1,-1],[-1,-1],[-1,-1],[-1,-1],[-1,-1],[-1,-1],[-1,-1],[-1,-1],[-1,-1],[-1,-1],[-1,-1],[-1,-1]]],"music_source":"","props":{"9;0":{"props":{"dialogue":{"propType":"dialogue","value":"welcome"}},"src":"props/prop.rprop"}},"start_pos":[9,2],"tileSize":48,"tileset":"tilesets/tiles.rtiles","width":20} \ No newline at end of file diff --git a/resources/defaults/props/prop.rprop b/resources/defaults/props/prop.rprop new file mode 100644 index 00000000..fe430640 --- /dev/null +++ b/resources/defaults/props/prop.rprop @@ -0,0 +1,17 @@ +{ + "atlas_rect": [ + 0, + 0, + 16, + 16 + ], + "collision_rect": [ + 0, + 8, + 16, + 8 + ], + "has_interactable": true, + "image": "images/prop.png", + "interactable_type": "dialogue" +} diff --git a/resources/defaults/sounds/Text 1.wav b/resources/defaults/sounds/Text 1.wav new file mode 100644 index 00000000..7b676564 Binary files /dev/null and b/resources/defaults/sounds/Text 1.wav differ diff --git a/resources/defaults/tilesets/actorTiles.rtiles b/resources/defaults/tilesets/actorTiles.rtiles new file mode 100644 index 00000000..c16ae7a5 --- /dev/null +++ b/resources/defaults/tilesets/actorTiles.rtiles @@ -0,0 +1 @@ +{"source":"images/character.png","tileHeight":16.0,"tileSize":16.0,"tileWidth":16.0} \ No newline at end of file diff --git a/resources/defaults/tilesets/tiles.rtiles b/resources/defaults/tilesets/tiles.rtiles new file mode 100644 index 00000000..1da5766c --- /dev/null +++ b/resources/defaults/tilesets/tiles.rtiles @@ -0,0 +1,6 @@ +{ + "source": "images/Hills.png", + "tileSize": 16, + "tileWidth": 16, + "tileHeight": 16 +} diff --git a/resources/projectsettings.png b/resources/projectsettings.png new file mode 100644 index 00000000..32db54b7 Binary files /dev/null and b/resources/projectsettings.png differ diff --git a/resources/scripts/dialogue.lua b/resources/scripts/dialogue.lua index b1292c1a..82d65d05 100644 --- a/resources/scripts/dialogue.lua +++ b/resources/scripts/dialogue.lua @@ -1,57 +1,3 @@ function interact() Interface.OpenDialogue(props.dialogue) - - room = World.GetRoom() - player = World.GetPlayer() - pos = player:GetPosition() - - actor = player:GetActor() - - actorpos = actor:GetPosition() - - print(actorpos.x) - print(actorpos.y) - - col = room:GetCollisions() - print(col:Exists(Vector2.new(0, 3))) - - inters = room:GetInteractables() - print(inters:Exists(Vector2.new(12, 0))) - - thispos = this:GetPosition() - - print(this:GetPosition().x) - print(this:GetPosition().y) - inters:Remove(Vector2.new(12, 0)) - - inters:Push(Vector2.new(14, 0), "dialogue") - newInter = inters:GetAt(Vector2.new(14, 0)) - newInter:SetProp("dialogue", "mydiag") - - room:GetActors():Push(Vector2.new(2, 2), "krisactor", "sudo") - - room:GetTileMap():SetTile(thispos, Vector2.new(1, 1)) - - GameState.Set("test_nil", nil); - GameState.Set("test_bool", true); - GameState.Set("test_int1", 50); - GameState.Set("test_int2", 4611686018427387904); - GameState.Set("test_double", 3.14); - GameState.Set("test_string", "hello"); - GameState.Set("test_table1", { 1, 2, "test" }); - GameState.Set("test_table2", { key = "test" }); - GameState.Set("test_table3", { key = "test", 2, 4 }); - - print(GameState.Get("test_nil"), type(GameState.Get("test_nil"))) - print(GameState.Get("test_bool"), type(GameState.Get("test_bool"))) - print(GameState.Get("test_int1"), type(GameState.Get("test_int1"))) - print(GameState.Get("test_int2"), type(GameState.Get("test_int2"))) - print(GameState.Get("test_double"), type(GameState.Get("test_double"))) - print(GameState.Get("test_string"), type(GameState.Get("test_string"))) - print(GameState.Get("test_table1"), type(GameState.Get("test_table1"))) - print(GameState.Get("test_table2"), type(GameState.Get("test_table2"))) - print(GameState.Get("test_table3"), type(GameState.Get("test_table3"))) - - print(Direction.LEFT) - actor:PlayAnimation(Direction.LEFT) end diff --git a/resources/translations/bg.json b/resources/translations/bg.json index 579d0428..4e0eed38 100644 --- a/resources/translations/bg.json +++ b/resources/translations/bg.json @@ -60,7 +60,38 @@ }, "dialogueview": { "add_new_line": "Добавете част", - "has_a_portrait": "Има портретно изображение?" + "has_a_portrait": "Има портрет?", + "select_a_font": "Изберете шрифт..", + "select_a_color": "Изберете цвят..", + "select_a_text_size": "Размер на текста..", + "add_a_delay": "Дoбавете забавяне..", + "add_option": "Добавете опция", + "color": { + "lightgray": "Светло сиво", + "gold": "Златно", + "pink": "Розово", + "green": "Зелени", + "skyblue": "Небесно синьо", + "purple": "Лилаво", + "beige": "Бежово", + "magenta": "Магента", + "gray": "Сиво", + "yellow": "Жълто", + "red": "Червено", + "lime": "Лимоново", + "blue": "Синьо", + "violet": "Виолетово", + "brown": "Кафяво", + "white": "Бяло", + "darkgray": "Тъмно синьо", + "orange": "Оранжево", + "maroon": "Кафяво-червено", + "darkgreen": "Тъмно зелено", + "darkblue": "Тъмно синьо", + "darkpurple": "Тъмно лилаво", + "darkbrown": "Тъмно Brown", + "black": "Черно" + } }, "tilesetview": { "tile_width": "Ширина на плочка", @@ -96,6 +127,11 @@ "edit_anim_data": "Редактирай анимация", "is_non_idle": "е анимация на вървене?" }, + "interactableview": { + "display_name": "Име", + "script": "Скрипт", + "on_touch": "Извикай при допир?" + }, "toolbar": { "play": "Пусни игра", "build": "Компилирай игра" @@ -116,6 +152,76 @@ "folder": "Папка", "confirm": "Потвърди", "cancel": "Отмени" + }, + "project_settings": { + "_label": "Настройки на проекта", + "title": "Име", + "save": "Запази", + "program": { + "_label": "Програма", + "title": "Име", + "version": "Версия", + "program_icon": "Икона на програма", + "window_width": "Ширина на прозореца", + "window_height": "Височина на прозореца", + "is_resizable": "Позволи оразмеряване?", + "window_mode": "Режим на прозореца", + "target_fps": "Кадри в секунда" + }, + "game": { + "_label": "Игра", + "default_room": "Първоначална стая", + "player_actor": "Актьор на играча", + "tile_size": "Размер на плочка", + "debug_draw": "Дебъгерно рисуване", + "export_image_scales": "Експортирани размери на изобр.", + "export_font_sizes": "Експортиране размери на шрифтовете" + } + }, + "new_prop": { + "title": "Нов обект", + "name": "Име", + "type": "Тип", + "submit": "Създай" + }, + "delaywindow": { + "add_a_delay": "Добави забавяне", + "description": "Забавяне в секунди.", + "confirm": "ДОбави" + }, + "edit_prop": { + "title": "Редактирай обект", + "type": "Тип", + "submit": "Потвърди", + "remove": "Премахни" + }, + "delete_file": { + "title": "Сигурни ли сте?", + "yes": "Да", + "no": "Не", + "ok": "Ок", + "room_must_exist": "Трябва да имате поне една стая..", + "room_cannot_be_deleted": "Не може да изтриете стаята, зададена по подразбиране.", + "player_actor_must_exist": "Трябва да имате playerActor файл.", + "player_actor_cannot_be_deleted": "Не може да изтриете актьора на играча." + }, + "add_dialogue_option": { + "title": "Добавяне на опция", + "name": "Текст", + "dialogue": "Диалог", + "submit": "Добави" + }, + "edit_dialogue_option": { + "title": "Редактиране на опция", + "name": "Текст", + "dialogue": "Диалог", + "submit": "Потвърди", + "remove": "Премахни" + }, + "edit_list_field": { + "title": "Редактиране на списък..", + "add": "Добави..", + "close": "Затвори" } }, "widget": { @@ -124,9 +230,20 @@ }, "hotkey_modifier": { "listening": "Слушам..." + }, + "propField": { + "interPropField": { + "remove": "Премахни" + } } }, "button": { - "go_back": "Върни се" + "go_back": "Върни се", + "restart": "Рестартирай", + "restart_later": "Рестартирай по-късно" + }, + "context_menu": { + "copy_full_path": "Копирай пълен път", + "delete": "Изтрий" } } \ No newline at end of file diff --git a/resources/translations/en_us.json b/resources/translations/en_us.json index c0e2bdce..0349d00e 100644 --- a/resources/translations/en_us.json +++ b/resources/translations/en_us.json @@ -34,7 +34,7 @@ "_label": "General", "language": "Language", "theme": "Theme", - "theme_notice": "It is recommended to restart the editor after switching theme!" + "theme_notice": "You need to restart the editor for the theme to take effect.\nUnsaved progress will be lost!" }, "hotkeys": { "_label": "Hotkeys", @@ -60,7 +60,38 @@ }, "dialogueview": { "add_new_line": "Add a new line", - "has_a_portrait": "Has a portrait?" + "has_a_portrait": "Has a portrait?", + "select_a_font": "Select a font...", + "select_a_color": "Select a color...", + "select_a_text_size": "Text Size...", + "add_a_delay": "Add delay...", + "add_option": "Add option", + "color": { + "lightgray": "Light Gray", + "gold": "Gold", + "pink": "Pink", + "green": "Green", + "skyblue": "Sky Blue", + "purple": "Purple", + "beige": "Beige", + "magenta": "Magenta", + "gray": "Gray", + "yellow": "Yellow", + "red": "Red", + "lime": "Lime", + "blue": "Blue", + "violet": "Violet", + "brown": "Brown", + "white": "White", + "darkgray": "Dark Gray", + "orange": "Orange", + "maroon": "Maroon", + "darkgreen": "Dark Green", + "darkblue": "Dark Blue", + "darkpurple": "Dark Purple", + "darkbrown": "Dark Brown", + "black": "Black" + } }, "tilesetview": { "tile_width": "Tile Width", @@ -96,6 +127,11 @@ "edit_anim_data": "Edit Animation Data", "is_non_idle": "Is Non-Idle Animation?" }, + "interactableview": { + "display_name": "Display Name", + "script": "Script", + "on_touch": "On Touch?" + }, "toolbar": { "play": "Play", "build": "Build" @@ -116,6 +152,76 @@ "folder": "Folder", "confirm": "Confirm", "cancel": "Cancel" + }, + "project_settings": { + "_label": "Project Settings", + "title": "Title", + "save": "Save", + "program": { + "_label": "Program", + "title": "Title", + "version": "Version", + "program_icon": "Program Icon", + "window_width": "Window Width", + "window_height": "Window Height", + "is_resizable": "Is Window Resizable?", + "window_mode": "Window Mode", + "target_fps": "Target FPS" + }, + "game": { + "_label": "Game", + "default_room": "Default Room", + "player_actor": "Player Actor", + "tile_size": "Tile Size", + "debug_draw": "Debug Draw", + "export_image_scales": "Export Image Scales", + "export_font_sizes": "Export Font Sizes" + } + }, + "new_prop": { + "title": "New Prop", + "name": "Name", + "type": "Type", + "submit": "Create" + }, + "delaywindow": { + "add_a_delay": "Add delay...", + "description": "Amount of delay to add in seconds.", + "confirm": "Confirm" + }, + "edit_prop": { + "title": "Edit Prop", + "type": "Type", + "submit": "Submit", + "remove": "Remove" + }, + "delete_file": { + "title": "Are you sure?", + "yes": "Yes", + "no": "No", + "ok": "Ok", + "room_must_exist": "You must have at least one Room.", + "room_cannot_be_deleted": "You cannot delete the default Room.", + "player_actor_must_exist": "You must have a playerActor file.", + "player_actor_cannot_be_deleted": "You cannot delete the Player's Actor." + }, + "add_dialogue_option": { + "title": "Add a Dialogue Option", + "name": "Option Name", + "dialogue": "Dialogue", + "submit": "Add" + }, + "edit_dialogue_option": { + "title": "Edit a Dialogue Option", + "name": "Option Name", + "dialogue": "Dialogue", + "submit": "Submit", + "remove": "Remove" + }, + "edit_list_field": { + "title": "Edit List..", + "add": "Add..", + "close": "Close" } }, "widget": { @@ -124,9 +230,20 @@ }, "hotkey_modifier": { "listening": "Listening..." + }, + "propField": { + "interPropField": { + "remove": "Remove" + } } }, "button": { - "go_back": "Go Back" + "go_back": "Go Back", + "restart": "Restart", + "restart_later": "Restart Later" + }, + "context_menu": { + "copy_full_path": "Copy full path", + "delete": "Delete" } -} +} \ No newline at end of file diff --git a/resources/translations/tr.json b/resources/translations/tr.json index 7df71a1d..f3982c2b 100644 --- a/resources/translations/tr.json +++ b/resources/translations/tr.json @@ -1,132 +1,249 @@ { - "language": "Türkçe", - "menu": { - "file": { - "_label": "Dosya", - "new_project": "Yeni Proje", - "open_project": "Proje Aç", - "save_file": "Dosyayı Kaydet" - }, - "edit": { - "_label": "Düzenle", - "undo": "Geri Al", - "redo": "Yinele" - }, - "options": { - "_label": "Seçenekler", - "editor": "Düzenleyici Seçenekleri..." - }, - "about": { - "_label": "Bilgi", - "rpgpp": "RPG++ Hakkında...", - "rpgpp_description": "C++'da yazılmış, RPG oyun motoru." - } - }, - "screen": { - "starting": { - "get_started": "Başla!", - "description": "'Yeni Proje'ye tıklayarak yeni proje oluşturun, ya da 'Proje Aç' ile birini açın!", - "actions": "Eylemler", - "recent_projects": "Son Projeler" - }, - "options": { - "general": { - "_label": "Genel", - "language": "Dil", - "theme": "Tema", - "theme_notice": "Tema değiştirdikten sonra düzenleyici yeniden başlatmanız önerilir!" - }, - "hotkeys": { - "_label": "Kısayollar", - "close_tab": "Sekmeyi Kapat", - "new_project": "Yeni Proje", - "open_project": "Proje Aç", - "undo": "Geri Al", - "redo": "Yinele", - "save_file": "Dosyayı Kaydet", - "toggle_debug": "Hata Ayıklamayı Aç/Kapat", - "room_tool.edit": "Harita Araçları/Düzenle", - "room_tool.eraser": "Harita Araçları/Sil", - "room_tool.mouse": "Harita Araçları/Fare", - "room_tool.pen": "Harita Araçları/Kalem", - "room_tool.set_spoint": "Harita Araçları/Başlangıç Noktasını Seç", - "room_tool.toggle_bm": "Harita Araçları/Fırça Modunu Aç/Kapat" - } - }, - "project": { - "create_new_resource": "Yeni Kaynak", - "emptyview": { - "notice": "Hiç bir dosya ya da görünüş tanımlanmamıştır!" - }, - "dialogueview": { - "add_new_line": "Yeni satır ekle", - "has_a_portrait": "Portresi olacak mı?" - }, - "tilesetview": { - "tile_width": "Kare Genişliği", - "tile_height": "Kare Yüksekliği", - "texture": "Doku" - }, - "roomview": { - "mapwidth": "Harita Genişliği", - "mapheight": "Harita Yüksekliği", - "tileset_file": "Kare Seti Dosyası", - "enable_brush": "Fırça Modunu Aktifleştir", - "bg_music_file": "Arkaplan Müziği" - }, - "propview": { - "atlas": "Atlas Büyüklüğü", - "collision": "Çarpışma Karesi Büyüklüğü", - "has_interactable": "Interaktifi Varmı?", - "image": "Obje Fotoğrafı", - "interactable_type": "Interaktif Türü" - }, - "actorview": { - "dir0": "Aşağı (Boşta)", - "dir1": "Aşağı", - "dir2": "Yukarı (Boşta)", - "dir3": "Yukarı", - "dir4": "Sol (Boşta)", - "dir5": "Sol", - "dir6": "Sağ (Boşta)", - "dir7": "Sağ", - "play": "Oynat", - "pause": "Duraklat", - "is_non_idle": "Boşta Olmayan Animasyon Mu?", - "delete": "Kare Sil", - "edit_anim_data": "Animasyon Verisini Düzenle" - }, - "toolbar": { - "play": "Oyna", - "build": "Derle" - } - } - }, - "dialog": { - "new_file": { - "title": "Yeni Kaynak", - "name": "Dosya Adı", - "file": "Dosya", - "confirm": "Kabul Et", - "cancel": "İptal" - }, - "new_project": { - "title": "Yeni Proje", - "name": "Proje Adı", - "folder": "Klasör", - "confirm": "Kabul Et", - "cancel": "İptal" - } - }, - "widget": { - "filechooser": { - "select_a_file": "Dosya Seç" - }, - "hotkey_modifier": { - "listening": "Bir tuşa basın..." - } - }, - "button": { - "go_back": "Geri Git" - } -} + "language": "Türkçe", + "menu": { + "file": { + "_label": "Dosya", + "new_project": "Yeni Proje", + "open_project": "Proje Aç", + "save_file": "Dosyayı Kaydet" + }, + "edit": { + "_label": "Düzenle", + "undo": "Geri Al", + "redo": "Yinele" + }, + "options": { + "_label": "Seçenekler", + "editor": "Düzenleyici Seçenekleri..." + }, + "about": { + "_label": "Bilgi", + "rpgpp": "RPG++ Hakkında...", + "rpgpp_description": "C++'da yazılmış, RPG oyun motoru." + } + }, + "screen": { + "starting": { + "get_started": "Başla!", + "description": "'Yeni Proje'ye tıklayarak yeni proje oluşturun, ya da 'Proje Aç' ile birini açın!", + "actions": "Eylemler", + "recent_projects": "Son Projeler" + }, + "options": { + "general": { + "_label": "Genel", + "language": "Dil", + "theme": "Tema", + "theme_notice": "Tema değiştirdikten sonra etkili olması için düzenleyiciyi yeniden başlatın.\nKaydedilmiş değişiklikler silinecektir!" + }, + "hotkeys": { + "_label": "Kısayollar", + "close_tab": "Sekmeyi Kapat", + "new_project": "Yeni Proje", + "open_project": "Proje Aç", + "undo": "Geri Al", + "redo": "Yinele", + "save_file": "Dosyayı Kaydet", + "toggle_debug": "Hata Ayıklamayı Aç/Kapat", + "room_tool.edit": "Harita Araçları/Düzenle", + "room_tool.eraser": "Harita Araçları/Sil", + "room_tool.mouse": "Harita Araçları/Fare", + "room_tool.pen": "Harita Araçları/Kalem", + "room_tool.set_spoint": "Harita Araçları/Başlangıç Noktasını Seç", + "room_tool.toggle_bm": "Harita Araçları/Fırça Modunu Aç/Kapat" + } + }, + "project": { + "create_new_resource": "Yeni Kaynak", + "emptyview": { + "notice": "Hiç bir dosya ya da görünüş tanımlanmamıştır!" + }, + "dialogueview": { + "add_new_line": "Yeni satır ekle", + "has_a_portrait": "Portresi Varmı?", + "select_a_color": "Renk seçiniz...", + "select_a_text_size": "Yazı Boyutu...", + "select_a_font": "Yazıtipi Seçin...", + "add_a_delay": "Gecikme Ekleyin...", + "add_option": "Seçenek Ekle", + "color": { + "lightgray": "Açık Grey", + "gold": "Altın", + "pink": "Pembe", + "green": "Yeşil", + "skyblue": "Gökyüzü Mavisi", + "purple": "Mor", + "beige": "Bej", + "magenta": "Macenta", + "gray": "Grey", + "yellow": "Sarı", + "red": "Kırmızı", + "lime": "Misket", + "blue": "Mavi", + "violet": "Menekşe", + "brown": "Kahverengi", + "white": "Beyaz", + "darkgray": "Koyu Gri", + "orange": "Turuncu", + "maroon": "Bordo", + "darkgreen": "Koyu Yeşil", + "darkblue": "Koyu Mavi", + "darkpurple": "Koyu Mor", + "darkbrown": "Koyu Kahverengi", + "black": "Siyah" + } + }, + "tilesetview": { + "tile_width": "Kare Genişliği", + "tile_height": "Kare Yüksekliği", + "texture": "Doku" + }, + "roomview": { + "mapwidth": "Harita Genişliği", + "mapheight": "Harita Yüksekliği", + "tileset_file": "Kare Seti Dosyası", + "enable_brush": "Fırça Modunu Aktifleştir", + "bg_music_file": "Arkaplan Müziği" + }, + "propview": { + "atlas": "Atlas Büyüklüğü", + "collision": "Çarpışma Karesi Büyüklüğü", + "has_interactable": "Interaktifi Varmı?", + "image": "Obje Fotoğrafı", + "interactable_type": "Interaktif Türü" + }, + "actorview": { + "dir0": "Aşağı (Boşta)", + "dir1": "Aşağı", + "dir2": "Yukarı (Boşta)", + "dir3": "Yukarı", + "dir4": "Sol (Boşta)", + "dir5": "Sol", + "dir6": "Sağ (Boşta)", + "dir7": "Sağ", + "play": "Oynat", + "pause": "Duraklat", + "is_non_idle": "Boşta Olmayan Animasyon Mu?", + "delete": "Kare Sil", + "edit_anim_data": "Animasyon Verisini Düzenle" + }, + "interactableview": { + "display_name": "Görünüş Adı", + "script": "Betik", + "on_touch": "Dokunulduğunda?" + }, + "toolbar": { + "play": "Oyna", + "build": "Derle" + } + } + }, + "dialog": { + "new_file": { + "title": "Yeni Kaynak", + "name": "Dosya Adı", + "file": "Dosya", + "confirm": "Kabul Et", + "cancel": "İptal" + }, + "new_project": { + "title": "Yeni Proje", + "name": "Proje Adı", + "folder": "Klasör", + "confirm": "Kabul Et", + "cancel": "İptal" + }, + "project_settings": { + "_label": "Proje Ayarları", + "title": "Başlık", + "save": "Kaydet", + "program": { + "_label": "Uygulama", + "title": "Başlık", + "version": "Versiyon", + "program_icon": "Uygulama Simgesi", + "window_width": "Pencere Genişliği", + "window_height": "Pencere Uzunluğu", + "is_resizable": "Pencerenin Boyutu Değiştirilebilir mi?", + "window_mode": "Pencere Modu", + "target_fps": "Hedef FPS" + }, + "game": { + "_label": "Oyun", + "default_room": "Öntanımlı Oda", + "player_actor": "Oyuncunun Aktörü", + "tile_size": "Kare Boyutu", + "debug_draw": "Hata Ayıklamayı Çiz", + "export_image_scales": "Fotoğraf Boyutluklarını Dışarı Aktar", + "export_font_sizes": "Yazıtipi Boyutlarını Dışarı Aktar" + } + }, + "delete_file": { + "title": "Gerçekten Sil?", + "yes": "Evet", + "no": "Hayır", + "ok": "Tamam", + "room_must_exist": "En az bir odanız olması lazımdır.", + "room_cannot_be_deleted": "Öntanımlı odayı silemezsiniz.", + "player_actor_must_exist": "playerActor dosyanızın olması lazımdır.", + "player_actor_cannot_be_deleted": "Oyuncunun Aktörünü silemezsiniz." + }, + "new_prop": { + "title": "Yeni Obje", + "name": "Adı", + "type": "Tür", + "submit": "Oluştur" + }, + "delaywindow": { + "add_a_delay": "Gecikme Ekleyin...", + "description": "Saniye olarak eklenecek gecikme.", + "confirm": "Ekle" + }, + "edit_prop": { + "title": "Objeyi Düzenle", + "type": "Tür", + "submit": "Düzenle", + "remove": "Sil" + }, + "add_dialogue_option": { + "title": "Bir diyalog seçeneği ekleyin", + "name": "Seçenek İsmi", + "dialogue": "Diyalog", + "submit": "Ekle" + }, + "edit_dialogue_option": { + "title": "Diyalog Seçeneğini Düzenleyin", + "name": "Seçenek İsmi", + "dialogue": "Diyalog", + "submit": "Düzenle", + "remove": "Sil" + }, + "edit_list_field": { + "title": "Listeyi Düzenleyin...", + "add": "Ekle..", + "close": "Kapat" + } + }, + "widget": { + "filechooser": { + "select_a_file": "Dosya Seç" + }, + "hotkey_modifier": { + "listening": "Bir tuşa basın..." + }, + "propField": { + "interPropField": { + "remove": "Sil" + } + } + }, + "button": { + "go_back": "Geri Git", + "restart": "Yeniden Başlat", + "restart_later": "Sonra Yeniden Başlat" + }, + "context_menu": { + "copy_full_path": "Full yolunu kopyala", + "delete": "Sil" + } +} \ No newline at end of file diff --git a/resources/translations/vn.json b/resources/translations/vn.json index 1d7e0791..39b5c1bd 100644 --- a/resources/translations/vn.json +++ b/resources/translations/vn.json @@ -37,7 +37,7 @@ "_label": "Chung", "language": "Ngôn ngữ", "theme": "Chủ đề", - "theme_notice": "Để áp dụng chủ đề mới, vui lòng khởi động lại phần mềm!" + "theme_notice": "Để áp dụng chủ đề, vui lòng khởi động lại phần mềm.\n Lưu ý rằng tiến trình chưa lưu sẽ bị mất nếu khởi động lại!" }, "hotkeys": { "_label": "Phím Tắt", @@ -63,7 +63,38 @@ }, "dialogueview": { "add_new_line": "Tạo hội thoại mới", - "has_a_portrait": "Hiển thị ảnh hội thoại?" + "has_a_portrait": "Hiển thị ảnh hội thoại?", + "select_a_color": "Chọn màu", + "select_a_font": "Chọn phông chữ", + "select_a_text_size": "Chọn kích cỡ chữ", + "add_a_delay": "Thêm độ trễ", + "add_option": "Thêm tùy chọn", + "color": { + "lightgray": "Xám nhạt", + "gold": "Vàng", + "pink": "Hồng", + "green": "Xanh lá", + "skyblue": "Xanh da trời đậm", + "purple": "Đỏ tía", + "beige": "Be", + "magenta": "Hồng sẫm", + "gray": "Xám", + "yellow": "Vàng", + "red": "Đỏ", + "lime": "Vàng chanh", + "blue": "Xanh", + "violet": "Tím", + "brown": "Nâu", + "white": "Trắng", + "darkgray": "Xám đậm", + "orange": "Cam", + "maroon": "Nâu sẫm", + "darkgreen": "Xanh lá đậm", + "darkblue": "Xanh đậm", + "darkpurple": "Tía đậm", + "darkbrown": "Nâu đậm", + "black": "Đen" + } }, "tilesetview": { "tile_width": "Độ rộng Tile", @@ -102,7 +133,11 @@ "edit_anim_data": "Chỉnh sửa dữ liệu animation", "is_non_idle": "Có phải animation?" }, - + "interactableview": { + "display_name": "Tên hiển thị", + "script": "Tệp Script", + "on_touch": "Kích hoạt khi chạm?" + }, "toolbar": { "play": "Chạy chương trình", "build": "Dịch và tạo chương trình" @@ -125,6 +160,76 @@ "folder": "Thư mục", "confirm": "Tạo", "cancel": "Hủy" + }, + "project_settings": { + "_label": "Cấu hình dự án", + "title": "Tên dự án", + "save": "Lưu", + "program": { + "_label": "Phần mềm", + "title": "Tên", + "version": "Phiên bản", + "program_icon": "Biểu tượng", + "window_width": "Chiều rộng cửa sổ", + "window_height": "Chiều cao cửa sổ", + "is_resizable": "Cửa sổ có thể thay đổi kích cỡ?", + "window_mode": "Chế độ cửa sổ", + "target_fps": "FPS" + }, + "game": { + "_label": "Trò chơi", + "default_room": "Room mặc định", + "player_actor": "Actor người chơi", + "tile_size": "Kích cỡ Tile", + "debug_draw": "Vẽ gỡ lỗi", + "export_image_scales": "Kích cỡ xuất hình ảnh", + "export_font_sizes": "Kích cỡ xuất phông chữ" + } + }, + "new_prop": { + "title": "Tạo Prop mới", + "name": "Tên", + "type": "Loại", + "submit": "Tạo" + }, + "delaywindow": { + "add_a_delay": "Thêm độ trễ", + "description": "Thời gian độ trễ để thêm trong đơn vị giây.", + "confirm": "Xác nhận" + }, + "edit_prop": { + "title": "Chỉnh sửa Prop", + "type": "Loại", + "submit": "Sửa", + "remove": "Xóa" + }, + "delete_file": { + "title": "Bạn chắc có muốn xóa không?", + "yes": "Có", + "no": "Không", + "ok": "Okay", + "room_must_exist": "Lỗi: Dự án phải có ít nhất một phòng.", + "room_cannot_be_deleted": "Lỗi: Bạn không thể xóa phòng mặc định.", + "player_actor_must_exist": "Lỗi: Bạn phải có tệp tin playerActor.", + "player_actor_cannot_be_deleted": "Lỗi: Bạn không thể xóa Actor người chơi." + }, + "add_dialogue_option": { + "title": "Tạo tùy chọn hội thoại", + "name": "Tên tùy chọn", + "dialogue": "Hội thoại", + "submit": "Tạo" + }, + "edit_dialogue_option": { + "title": "Chỉnh sửa tùy chọn hội thoại", + "name": "Tên tùy chọn", + "dialogue": "Hội thoại", + "submit": "Sửa", + "remove": "Xóa" + }, + "edit_list_field": { + "title": "Sửa danh sách", + "add": "Thêm", + "close": "Thoát" } }, @@ -134,10 +239,21 @@ }, "hotkey_modifier": { "listening": "Đang nhận phím..." + }, + "propField": { + "interPropField": { + "remove": "Xóa" + } } }, "button": { - "go_back": "Quay lại" + "go_back": "Quay lại", + "restart": "Khởi động lại", + "restart_later": "Khởi động lại sau" + }, + "context_menu": { + "copy_full_path": "Sao chép đường dẫn", + "delete": "Xóa" } } diff --git a/src/actor.cpp b/src/actor.cpp index 4bb39e98..f7d97d70 100644 --- a/src/actor.cpp +++ b/src/actor.cpp @@ -1,17 +1,21 @@ #include "actor.hpp" -#include "game.hpp" -#include "gamedata.hpp" -#include "tileset.hpp" + +#include +#include + #include #include #include #include #include #include -#include -#include #include #include + +#include "game.hpp" +#include "gamedata.hpp" +#include "interactable.hpp" +#include "tileset.hpp" using json = nlohmann::json; Actor::Actor(const std::string &fileName) { @@ -34,12 +38,13 @@ Actor::Actor(const std::string &fileName) { int height = collisionInfo.at(3); this->collisionRect = - Rectangle{static_cast(x), static_cast(y), - static_cast(width), static_cast(height)}; + Rectangle{static_cast(x), static_cast(y), static_cast(width), static_cast(height)}; this->tileSetSource = j.at("tileset"); this->tileSet = std::make_unique(tileSetSource); + this->interactable = std::make_unique(); + for (int i = 0; i < 8; i++) { animations[i] = std::vector(); } @@ -65,16 +70,14 @@ Actor::Actor(const std::string &fileName) { std::vector> right = j.at("animations").at("right"); addAnimationFrames(RPGPP_RIGHT, right); - std::vector> rightIdle = - j.at("animations").at("right-idle"); + std::vector> rightIdle = j.at("animations").at("right-idle"); addAnimationFrames(RPGPP_RIGHT_IDLE, rightIdle); Vector2 defaultTileAtlasPos = animations[currentAnimation].at(0); this->tile = tileSet->getTile(defaultTileAtlasPos); } -Actor::Actor(std::unique_ptr tileSet, Vector2 atlasPos, - std::string tileSetSource) { +Actor::Actor(std::unique_ptr tileSet, Vector2 atlasPos, std::string tileSetSource) { this->sourcePath = ""; this->tilePosition = Vector2{-1, -1}; this->position = Vector2{0, 0}; @@ -88,6 +91,8 @@ Actor::Actor(std::unique_ptr tileSet, Vector2 atlasPos, this->currentFrame = 0; this->currentAnimation = RPGPP_DOWN_IDLE; + this->interactable = std::make_unique(); + for (int i = 0; i < 8; i++) { animations[i] = std::vector(); } @@ -115,8 +120,7 @@ Actor::Actor(std::unique_ptr tileSet, Vector2 atlasPos, // Default collision box.. Vector2 atlasTileSize = this->tileSet->getTileSize(); this->collisionRect = - Rectangle{0, (atlasTileSize.y * RPGPP_DRAW_MULTIPLIER) / 2, - (atlasTileSize.x * RPGPP_DRAW_MULTIPLIER), + Rectangle{0, (atlasTileSize.y * RPGPP_DRAW_MULTIPLIER) / 2, (atlasTileSize.x * RPGPP_DRAW_MULTIPLIER), (atlasTileSize.y * RPGPP_DRAW_MULTIPLIER) / 2}; } @@ -130,14 +134,14 @@ Actor::Actor(const ActorBin &bin) { this->currentAnimation = RPGPP_DOWN_IDLE; // tileset - this->tileSet = - std::make_unique(Game::getBin().tilesets.at(bin.tileSetName)); + this->tileSet = std::make_unique(Game::getBin().tilesets.at(bin.tileSetName)); // collision - this->collisionRect = Rectangle{static_cast(bin.collision.x), - static_cast(bin.collision.y), - static_cast(bin.collision.width), - static_cast(bin.collision.height)}; + this->collisionRect = Rectangle{static_cast(bin.collision.x), static_cast(bin.collision.y), + static_cast(bin.collision.width), static_cast(bin.collision.height)}; + + // interactable + this->interactable = std::make_unique(); // animations for (int i = 0; i < 8; i++) { @@ -180,38 +184,36 @@ json Actor::dumpJson() { auto direction = static_cast(i); std::string keyName = "untitled"; switch (direction) { - case RPGPP_DOWN_IDLE: - keyName = "down-idle"; - break; - case RPGPP_DOWN: - keyName = "down"; - break; - case RPGPP_UP_IDLE: - keyName = "up-idle"; - break; - case RPGPP_UP: - keyName = "up"; - break; - case RPGPP_LEFT_IDLE: - keyName = "left-idle"; - break; - case RPGPP_LEFT: - keyName = "left"; - break; - case RPGPP_RIGHT_IDLE: - keyName = "right-idle"; - break; - case RPGPP_RIGHT: - keyName = "right"; - break; + case RPGPP_DOWN_IDLE: + keyName = "down-idle"; + break; + case RPGPP_DOWN: + keyName = "down"; + break; + case RPGPP_UP_IDLE: + keyName = "up-idle"; + break; + case RPGPP_UP: + keyName = "up"; + break; + case RPGPP_LEFT_IDLE: + keyName = "left-idle"; + break; + case RPGPP_LEFT: + keyName = "left"; + break; + case RPGPP_RIGHT_IDLE: + keyName = "right-idle"; + break; + case RPGPP_RIGHT: + keyName = "right"; + break; } animsVec[keyName] = framesVec; } - json j = {{"tileset", tileSetSource}, - {"collision", collisionVec}, - {"animations", animsVec}}; + json j = {{"tileset", tileSetSource}, {"collision", collisionVec}, {"animations", animsVec}}; return j; } @@ -220,13 +222,9 @@ void Actor::unload() const { tileSet->unload(); } int Actor::getCurrentFrame() const { return this->currentFrame; } -int Actor::getAnimationCount() const { - return this->getAnimationRaw(this->currentAnimation).size(); -} +int Actor::getAnimationCount() const { return this->getAnimationRaw(this->currentAnimation).size(); } -Direction Actor::getAnimationDirection() const { - return this->currentAnimation; -} +Direction Actor::getAnimationDirection() const { return this->currentAnimation; } Vector2 Actor::getCurrentAnimationAtlas() const { return this->getAnimationRaw(this->currentAnimation).at(currentFrame); @@ -241,11 +239,9 @@ void Actor::setAnimationFrame(int frameIndex) { Vector2 atlasTileSize = tileSet->getTileSize(); Vector2 atlasPos = animations[currentAnimation].at(currentFrame); - atlasPos = - Vector2{atlasPos.x * atlasTileSize.x, atlasPos.y * atlasTileSize.y}; + atlasPos = Vector2{atlasPos.x * atlasTileSize.x, atlasPos.y * atlasTileSize.y}; - if (this->onFrameChanged != nullptr) - this->onFrameChanged(this->currentFrame); + if (this->onFrameChanged != nullptr) this->onFrameChanged(this->currentFrame); this->tile = tileSet->getTile(atlasPos); } @@ -253,8 +249,7 @@ void Actor::setAnimationFrame(int frameIndex) { Rectangle Actor::getCurrentAnimationRectangle() const { const auto &atlasPos = this->getCurrentAnimationAtlas(); const auto &atlasSize = this->getTileSet().getTileSize(); - return {atlasPos.x * atlasSize.x, atlasPos.y * atlasSize.y, atlasSize.x, - atlasSize.y}; + return {atlasPos.x * atlasSize.x, atlasPos.y * atlasSize.y, atlasSize.x, atlasSize.y}; } void Actor::update() { @@ -270,7 +265,6 @@ void Actor::update() { if (currentFrame >= this->getAnimationCount()) { if (currentFrame >= this->getAnimationCount()) { - currentFrame = 0; if (tempAnimIsPlayed) { currentAnimation = lastAnimation; @@ -288,8 +282,7 @@ void Actor::draw() const { constexpr auto origin = Vector2{0.0f, 0.0f}; constexpr float rotation = 0.0f; const Vector2 atlasTileSize = tileSet->getTileSize(); - auto worldTileSize = Vector2{atlasTileSize.x * RPGPP_DRAW_MULTIPLIER, - atlasTileSize.y * RPGPP_DRAW_MULTIPLIER}; + auto worldTileSize = Vector2{atlasTileSize.x * RPGPP_DRAW_MULTIPLIER, atlasTileSize.y * RPGPP_DRAW_MULTIPLIER}; // texture Texture texture = this->tileSet->getTexture(); @@ -298,30 +291,37 @@ void Actor::draw() const { Vector2 atlasCoords = this->tile.getAtlasCoords(); // build rects - auto atlasRect = Rectangle{atlasCoords.x, atlasCoords.y, atlasTileSize.x, - atlasTileSize.y}; - auto worldRect = - Rectangle{position.x, position.y, worldTileSize.x, worldTileSize.y}; + auto atlasRect = Rectangle{atlasCoords.x, atlasCoords.y, atlasTileSize.x, atlasTileSize.y}; + auto worldRect = Rectangle{position.x, position.y, worldTileSize.x, worldTileSize.y}; // draw it DrawTexturePro(texture, atlasRect, worldRect, origin, rotation, WHITE); - // draw collision rect.. - auto collisionDebugColor = GRAY; - collisionDebugColor.a = (255 / 2); + bool debugDraw = true; + + if (Game::isUsingBin()) { + debugDraw = Game::getBin().gameSet.debugDraw; + } + + if (debugDraw) { + // draw collision rect.. + auto collisionDebugColor = GRAY; + collisionDebugColor.a = (255 / 2); - Rectangle drawnCollisionRect = getCollisionRect(Vector2{0, 0}); - DrawRectanglePro(drawnCollisionRect, origin, rotation, collisionDebugColor); + Rectangle drawnCollisionRect = getCollisionRect(Vector2{0, 0}); + DrawRectanglePro(drawnCollisionRect, origin, rotation, collisionDebugColor); + + // let me draw the collision center + DrawCircleV(getCollisionCenter(), 2.5f, MAROON); + } } std::string Actor::getSourcePath() const { return sourcePath; } Rectangle Actor::getRect() const { - if (tileSet == nullptr) - return Rectangle{0, 0, 0, 0}; + if (tileSet == nullptr) return Rectangle{0, 0, 0, 0}; Vector2 atlasTileSize = tileSet->getTileSize(); - auto result = Rectangle{position.x, position.y, - atlasTileSize.x * RPGPP_DRAW_MULTIPLIER, + auto result = Rectangle{position.x, position.y, atlasTileSize.x * RPGPP_DRAW_MULTIPLIER, atlasTileSize.y * RPGPP_DRAW_MULTIPLIER}; return result; } @@ -340,21 +340,15 @@ Vector2 Actor::getPosition() const { return position; } void Actor::setTilePosition(Vector2 newPosition, Vector2 tileSize) { Vector2 actorTileSize = tileSet->getTileSize(); auto absolutePos = - Vector2{newPosition.x * tileSize.x * RPGPP_DRAW_MULTIPLIER, - newPosition.y * tileSize.y * RPGPP_DRAW_MULTIPLIER}; + Vector2{newPosition.x * tileSize.x * RPGPP_DRAW_MULTIPLIER, newPosition.y * tileSize.y * RPGPP_DRAW_MULTIPLIER}; float xDiff = 0; - if ((tileSet->getTileWidth() * RPGPP_DRAW_MULTIPLIER) > - (tileSize.x * RPGPP_DRAW_MULTIPLIER)) { - xDiff = ((tileSet->getTileWidth() * RPGPP_DRAW_MULTIPLIER) - - (tileSize.x * RPGPP_DRAW_MULTIPLIER)) / - 2; + if ((tileSet->getTileWidth() * RPGPP_DRAW_MULTIPLIER) > (tileSize.x * RPGPP_DRAW_MULTIPLIER)) { + xDiff = ((tileSet->getTileWidth() * RPGPP_DRAW_MULTIPLIER) - (tileSize.x * RPGPP_DRAW_MULTIPLIER)) / 2; } - auto resultVector = - Vector2{absolutePos.x - xDiff, - absolutePos.y - ((actorTileSize.y * RPGPP_DRAW_MULTIPLIER) - - (tileSize.y * RPGPP_DRAW_MULTIPLIER))}; + auto resultVector = Vector2{absolutePos.x - xDiff, absolutePos.y - ((actorTileSize.y * RPGPP_DRAW_MULTIPLIER) - + (tileSize.y * RPGPP_DRAW_MULTIPLIER))}; this->position = resultVector; this->tilePosition = newPosition; } @@ -370,31 +364,26 @@ void Actor::moveByVelocity(Vector2 velocity) { Rectangle Actor::getCollisionRect(Vector2 velocity) const { Vector2 newPos = Vector2Add(position, velocity); auto result = - Rectangle{newPos.x + collisionRect.x, newPos.y + collisionRect.y, - collisionRect.width, collisionRect.height}; + Rectangle{newPos.x + collisionRect.x, newPos.y + collisionRect.y, collisionRect.width, collisionRect.height}; return result; } Vector2 Actor::getCollisionCenter() const { - Vector2 result = {position.x + (collisionRect.width / 2), - position.y + (collisionRect.height / 2)}; + Vector2 result = {position.x + collisionRect.x + (collisionRect.width / 2), + position.y + collisionRect.y + (collisionRect.height / 2)}; return result; } -void Actor::addAnimationFrame(Direction id, Vector2 atlasPos) { - animations[id].push_back(atlasPos); -} +void Actor::addAnimationFrame(Direction id, Vector2 atlasPos) { animations[id].push_back(atlasPos); } void Actor::removeAnimationFrame(Direction id, int frameIndex) { if (currentFrame == frameIndex) { currentFrame = 0; } - if (frameIndex == 0) - return; + if (frameIndex == 0) return; // how do we know the frame was valid on index side? - assert(frameIndex < animations[id].size() && - "requested animation index is invalid"); + assert(frameIndex < animations[id].size() && "requested animation index is invalid"); animations[id].erase(animations[id].begin() + frameIndex); } @@ -402,13 +391,11 @@ void Actor::setAnimationFrame(Direction id, int frameIndex, Vector2 atlasTile) { animations[id][frameIndex] = atlasTile; } -void Actor::addAnimationFrames(const Direction id, - const std::vector> &frames) { +void Actor::addAnimationFrames(const Direction id, const std::vector> &frames) { for (int i = 0; i < frames.size(); i++) { int x = frames.at(i).at(0); int y = frames.at(i).at(1); - animations[id].push_back( - Vector2{static_cast(x), static_cast(y)}); + animations[id].push_back(Vector2{static_cast(x), static_cast(y)}); } } @@ -459,24 +446,28 @@ Rectangle Actor::getCollisionRect() const { return collisionRect; } void Actor::setCollisionRect(Rectangle rect) { this->collisionRect = rect; } -Vector2 calcActorTilePos(Vector2 newPosition, Vector2 worldTileSize, - TileSet *tileSet) { +Vector2 calcActorTilePos(Vector2 newPosition, Vector2 worldTileSize, TileSet *tileSet) { Vector2 actorTileSize = tileSet->getTileSize(); - auto absolutePos = - Vector2{newPosition.x * worldTileSize.x * RPGPP_DRAW_MULTIPLIER, - newPosition.y * worldTileSize.y * RPGPP_DRAW_MULTIPLIER}; + auto absolutePos = Vector2{newPosition.x * worldTileSize.x * RPGPP_DRAW_MULTIPLIER, + newPosition.y * worldTileSize.y * RPGPP_DRAW_MULTIPLIER}; float xDiff = 0; - if ((tileSet->getTileWidth() * RPGPP_DRAW_MULTIPLIER) > - (worldTileSize.x * RPGPP_DRAW_MULTIPLIER)) { - xDiff = ((tileSet->getTileWidth() * RPGPP_DRAW_MULTIPLIER) - - (worldTileSize.x * RPGPP_DRAW_MULTIPLIER)) / - 2; + if ((tileSet->getTileWidth() * RPGPP_DRAW_MULTIPLIER) > (worldTileSize.x * RPGPP_DRAW_MULTIPLIER)) { + xDiff = ((tileSet->getTileWidth() * RPGPP_DRAW_MULTIPLIER) - (worldTileSize.x * RPGPP_DRAW_MULTIPLIER)) / 2; } - auto resultVector = - Vector2{absolutePos.x - xDiff, - absolutePos.y - ((actorTileSize.y * RPGPP_DRAW_MULTIPLIER) - - (worldTileSize.y * RPGPP_DRAW_MULTIPLIER))}; + auto resultVector = Vector2{absolutePos.x - xDiff, absolutePos.y - ((actorTileSize.y * RPGPP_DRAW_MULTIPLIER) - + (worldTileSize.y * RPGPP_DRAW_MULTIPLIER))}; return resultVector; } + +bool Actor::hasInteractable() { return ownsInteractable; } + +void Actor::setHasInteractable(bool value) { ownsInteractable = value; } + +Interactable *Actor::getInteractable() { return interactable.get(); } + +void Actor::setInteractableFromPath(const std::string &path) { + interactable = std::make_unique(path); + ownsInteractable = true; +} diff --git a/src/actorContainer.cpp b/src/actorContainer.cpp index 5048dcce..6f188152 100644 --- a/src/actorContainer.cpp +++ b/src/actorContainer.cpp @@ -1,44 +1,29 @@ #include "actorContainer.hpp" -#include "actor.hpp" -#include "game.hpp" -#include "raylib.h" + #include #include #include -ActorContainer::ActorContainer() { - actors = std::map>{}; -} +#include "actor.hpp" +#include "game.hpp" +#include "raylib.h" -std::map> &ActorContainer::getActors() { - return actors; -} +ActorContainer::ActorContainer() { actors = std::map>{}; } -Actor &ActorContainer::getActor(const std::string &name) { - return *actors[name]; -} +std::map> &ActorContainer::getActors() { return actors; } + +Actor &ActorContainer::getActor(const std::string &name) { return *actors[name]; } -void ActorContainer::addActor(Vector2 pos, const std::string &typeName, - const std::string &roomName) { +void ActorContainer::addActor(Vector2 pos, const std::string &typeName, const std::string &roomName) { if (Game::getBin().actors.count(typeName) > 0) { - auto newActor = - std::make_unique(Game::getBin().actors[typeName]); - newActor->setTilePosition(pos, Game::getWorld() - .getRoom() - .getTileMap() - ->getTileSet() - ->getTileSize()); + auto newActor = std::make_unique(Game::getBin().actors[typeName]); + newActor->setTilePosition(pos, Game::getWorld().getRoom().getTileMap()->getTileSet()->getTileSize()); actors[roomName] = std::move(newActor); } else { - throw std::runtime_error( - TextFormat("This Actor does not exist: %s", typeName.c_str())); + throw std::runtime_error(TextFormat("This Actor does not exist: %s", typeName.c_str())); } } -void ActorContainer::removeActor(const std::string &roomName) { - actors.erase(roomName); -} +void ActorContainer::removeActor(const std::string &roomName) { actors.erase(roomName); } -bool ActorContainer::actorExists(const std::string &roomName) { - return (actors.count(roomName) > 0); -} \ No newline at end of file +bool ActorContainer::actorExists(const std::string &roomName) { return (actors.count(roomName) > 0); } \ No newline at end of file diff --git a/src/atlasTile.cpp b/src/atlasTile.cpp index 6f05c00a..ba2130a4 100644 --- a/src/atlasTile.cpp +++ b/src/atlasTile.cpp @@ -1,4 +1,5 @@ #include "atlasTile.hpp" + #include AtlasTile::AtlasTile() { diff --git a/src/collisionsContainer.cpp b/src/collisionsContainer.cpp index 960570c8..5f41d023 100644 --- a/src/collisionsContainer.cpp +++ b/src/collisionsContainer.cpp @@ -1,7 +1,9 @@ #include "collisionsContainer.hpp" -#include "gamedata.hpp" + #include +#include "gamedata.hpp" + CollisionsContainer::CollisionsContainer() = default; void CollisionsContainer::pushCollision(IVector pos) { pushObject(pos, true); } diff --git a/src/colorRect.cpp b/src/colorRect.cpp index cde5390d..b6c4c505 100644 --- a/src/colorRect.cpp +++ b/src/colorRect.cpp @@ -1,4 +1,5 @@ #include "colorRect.hpp" + #include ColorRect::ColorRect() : rect(Rectangle{1, 1, 1, 1}), color() {} diff --git a/src/conversion.cpp b/src/conversion.cpp index a41701a5..5ccad76f 100644 --- a/src/conversion.cpp +++ b/src/conversion.cpp @@ -1,11 +1,8 @@ #include "conversion.hpp" + #include "gamedata.hpp" #include "raylib.h" -Vector2 fromIVector(const IVector &other) { - return {static_cast(other.x), static_cast(other.y)}; -} +Vector2 fromIVector(const IVector &other) { return {static_cast(other.x), static_cast(other.y)}; } -IVector fromVector2(const Vector2 &other) { - return {static_cast(other.x), static_cast(other.y)}; -} \ No newline at end of file +IVector fromVector2(const Vector2 &other) { return {static_cast(other.x), static_cast(other.y)}; } \ No newline at end of file diff --git a/src/dialogue.cpp b/src/dialogue.cpp index 3e76509e..579e73b9 100644 --- a/src/dialogue.cpp +++ b/src/dialogue.cpp @@ -1,9 +1,12 @@ #include "dialogue.hpp" + +#include +#include +#include + #include "dialogueBalloon.hpp" #include "dialogueParser.hpp" #include "raylib.h" -#include -#include Dialogue::Dialogue(const std::string &filePath) { DialogueBin result; @@ -11,19 +14,22 @@ Dialogue::Dialogue(const std::string &filePath) { try { json jsonObj = json::parse(fileTxt); - std::vector> diagVector = jsonObj.at("diag"); + std::vector diagVector = jsonObj.at("diag"); for (auto lineVec : diagVector) { - if (lineVec.size() == 4) { - DialogueLine line; - line.characterName = lineVec.at(0); - line.text = lineVec.at(1); - line.hasPortrait = std::stoi(lineVec.at(2)); - line.imageId = lineVec.at(3); + DialogueLine line; + line.characterName = lineVec.value("characterName", "Character"); + line.text = lineVec.value("text", "No text available!"); + line.hasPortrait = lineVec.value("hasPortrait", false); + line.imageId = lineVec.value("imageId", ""); - line.sections = parseDialogueContent(line.text); + line.sections = parseDialogueContent(line.text); - result.lines.push_back(line); + line.hasOptions = lineVec.value("hasOptions", false); + for (auto &jOption : lineVec.at("options")) { + line.options.push_back({jOption.at("name"), jOption.at("nextDialogue")}); } + + result.lines.push_back(line); } dialogueBin = result; @@ -35,13 +41,24 @@ Dialogue::Dialogue(const std::string &filePath) { } nlohmann::json Dialogue::dumpJson() { - std::vector> diagVec; + std::vector diagVec; for (DialogueLine line : dialogueBin.lines) { - std::vector lineVec; - lineVec.push_back(line.characterName); - lineVec.push_back(line.text); - lineVec.push_back((line.hasPortrait ? "1" : "0")); - lineVec.push_back(line.imageId); + auto lineVec = nlohmann::json::object(); + lineVec.push_back({"characterName", line.characterName}); + lineVec.push_back({"text", line.text}); + lineVec.push_back({"hasPortrait", line.hasPortrait}); + lineVec.push_back({"imageId", line.imageId}); + lineVec.push_back({"hasOptions", line.hasOptions}); + + auto optionsVec = std::vector{}; + + for (auto &option : line.options) { + auto optionsObj = nlohmann::json::object(); + optionsObj["name"] = option.title; + optionsObj["nextDialogue"] = option.nextDialogue; + optionsVec.push_back(optionsObj); + } + lineVec.push_back({"options", optionsVec}); diagVec.push_back(lineVec); } diff --git a/src/dialogueBalloon.cpp b/src/dialogueBalloon.cpp index 83be1db3..34687902 100644 --- a/src/dialogueBalloon.cpp +++ b/src/dialogueBalloon.cpp @@ -1,19 +1,23 @@ #include "dialogueBalloon.hpp" -#include "game.hpp" -#include "interfaceService.hpp" -#include + #include #include +#include + +#include "game.hpp" +#include "interfaceService.hpp" + DialogueBalloon::DialogueBalloon() = default; DialogueBalloon::DialogueBalloon(Rectangle rect) { + this->font = Game::getResources().getFont("LanaPixel"); this->rect = rect; - this->textRect = Rectangle{rect.x + 9, rect.y + 9, rect.width - (9 * 2), - rect.height - (9 * 2)}; + this->textRect = Rectangle{rect.x + 9, rect.y + 9, rect.width - (9 * 2), rect.height - (9 * 2)}; this->textPortraitRect = this->textRect; this->textPortraitRect.width -= this->textRect.height; this->textPortraitRect.x += this->textRect.height; + this->optionsRect = {rect.x + (rect.width - 180), rect.y - 8 - 180, 180, 180}; this->lineIndex = 0; this->sectionIndex = 0; @@ -38,7 +42,8 @@ void DialogueBalloon::update() { if (active) { if (firstCharTyped == false) { firstCharTyped = true; - Game::getSounds().playSound("Text 1"); + auto &soundId = dialogue.lines.at(lineIndex).sections.at(sectionIndex).sound; + Game::getSounds().playSound(soundId); return; } @@ -47,8 +52,17 @@ void DialogueBalloon::update() { finished = true; } + this->finishedTyping = finished; + if (IsKeyPressed(KEY_Z)) { if (finished) { + if (dialogue.lines.at(lineIndex).hasOptions) { + std::string newDialogue = dialogue.lines.at(lineIndex).options.at(hoveredOption).nextDialogue; + hideDialogue(); + showDialogue(Game::getBin().dialogues[newDialogue]); + return; + } + if (lineIndex == (dialogue.lines.size() - 1)) { hideDialogue(); } else { @@ -64,14 +78,34 @@ void DialogueBalloon::update() { lastSectionLen = 0; textPos = Vector2{0, 0}; + + appliedTag = false; + padding = 0.0f; + maxLineHeight = 0.0f; } } else { charIndex = (text.size() - 1); } } + if (dialogue.lines.at(lineIndex).hasOptions) { + if (IsKeyPressed(KEY_UP) && hoveredOption != 0) { + hoveredOption--; + } + if (IsKeyPressed(KEY_DOWN) && hoveredOption < (dialogue.lines.at(lineIndex).options.size() - 1)) { + hoveredOption++; + } + } + + if (delay) { + delayDuration -= (GetFrameTime() * static_cast(60.0f / 20.0f)); + if (delayDuration <= 0.0f) { + delay = false; + } + } + frameCounter++; - if (frameCounter > (60 / 20)) { + if (frameCounter > (60 / 20) && !delay) { frameCounter = 0; if (charIndex < text.size()) { charIndex++; @@ -79,7 +113,8 @@ void DialogueBalloon::update() { // play sound if (charIndex < text.size()) { if (text.at(charIndex) != ' ') { - Game::getSounds().playSound("Text 1"); + auto &soundId = dialogue.lines.at(lineIndex).sections.at(sectionIndex).sound; + Game::getSounds().playSound(soundId); } } } @@ -88,26 +123,20 @@ void DialogueBalloon::update() { } void DialogueBalloon::drawPortrait() const { - Texture2D texture = - Game::getResources().getTexture(dialogue.lines.at(lineIndex).imageId); - Rectangle source = Rectangle{0.0f, 0.0f, static_cast(texture.width), - static_cast(texture.height)}; - Rectangle dest = Rectangle{rect.x + 9, rect.y + 9, rect.height - (9 * 2), - rect.height - (9 * 2)}; + Texture2D texture = Game::getResources().getTexture(dialogue.lines.at(lineIndex).imageId); + Rectangle source = Rectangle{0.0f, 0.0f, static_cast(texture.width), static_cast(texture.height)}; + Rectangle dest = Rectangle{rect.x + 9, rect.y + 9, rect.height - (9 * 2), rect.height - (9 * 2)}; DrawTexturePro(texture, source, dest, Vector2{0, 0}, 0.0f, WHITE); } void DialogueBalloon::draw() { if (active) { - Font font = Game::getUi().getFont(); Texture uiTexture = Game::getUi().getTexture(); Vector2 origin = {0.0f, 0.0f}; NPatchInfo info = - NPatchInfo{Rectangle{0, 0, static_cast(uiTexture.width), - static_cast(uiTexture.height)}, - 3 * 3, 3 * 3, uiTexture.width - (3 * 3), - uiTexture.height - (3 * 3)}; + NPatchInfo{Rectangle{0, 0, static_cast(uiTexture.width), static_cast(uiTexture.height)}, + 3 * 3, 3 * 3, uiTexture.width - (3 * 3), uiTexture.height - (3 * 3)}; DrawTextureNPatch(uiTexture, info, rect, origin, 0.0f, WHITE); @@ -119,20 +148,23 @@ void DialogueBalloon::draw() { sectionIndex = 0; Vector2 charMeasure = Vector2{0, 0}; for (int i = 0; i < charIndex; i++) { - Color newTextColor = WHITE; - int size = 0; int idx = 0; for (auto section : dialogue.lines.at(lineIndex).sections) { if (i < (size + TextLength(section.text.c_str()))) { - sectionIndex = idx; - if (section.key == "red") { - newTextColor = RED; - } else if (section.key == "blue") { - newTextColor = BLUE; - } else if (section.key == "green") { - newTextColor = GREEN; + if (sectionIndex != idx) { + if (section.paddingMode == PADDING_PX) { + padding = section.padding; + } else { + padding = textRect.width * (section.padding / 100); + } + appliedTag = false; + if (section.newline) { + printf("newline tag.. \n"); + } } + sectionIndex = idx; + break; } else { size += TextLength(section.text.c_str()); @@ -140,28 +172,86 @@ void DialogueBalloon::draw() { idx++; } + if (maxLineHeight < charMeasure.y) { + maxLineHeight = charMeasure.y; + } + + auto &line = dialogue.lines.at(lineIndex); + auto §ion = dialogue.lines.at(lineIndex).sections.at(sectionIndex); + + if (fontName != section.font) { + font = Game::getResources().getFont(section.font); + fontName = section.font; + } + + if (section.key == "delay" || section.delay > 0) { + if (!delay) { + delay = true; + delayDuration = section.delay; + } + } + + if (!appliedTag) { + if (section.padding > 0.0f) { + charMeasure.x += padding; + appliedTag = true; + } + } + const char *subText = TextSubtext(text.c_str(), i, 1); - charP(charMeasure, subText, newTextColor); + charP(charMeasure, subText, line, section); - Vector2 newMeasure = MeasureTextEx( - font, TextSubtext(text.c_str(), i, 1), 13 * 3, 1.0f); + Vector2 newMeasure = MeasureTextEx(Game::getResources().getFont(section.font), + TextSubtext(text.c_str(), i, 1), section.textSize * 3, 1.0f); charMeasure = newMeasure; } + + if (finishedTyping && dialogue.lines.at(lineIndex).hasOptions) { + auto &line = dialogue.lines.at(lineIndex); + + DrawTextureNPatch(uiTexture, info, optionsRect, origin, 0.0f, WHITE); + + Vector2 optionTextPos = {optionsRect.x + 20, optionsRect.y + 20}; + int i = 0; + + for (auto &option : line.options) { + optionTextPos.y += (13 * 3) * i + (4 * i); + + Color optionTextColor = WHITE; + + if (hoveredOption == i) optionTextColor = YELLOW; + + DrawTextEx(Game::getResources().getFont("LanaPixel"), option.title.c_str(), optionTextPos, 13 * 3, 1.0, + optionTextColor); + + i++; + } + } } } -void DialogueBalloon::charP(Vector2 charMeasure, const char *c, Color color) { - Font font = Game::getUi().getFont(); +void DialogueBalloon::charP(Vector2 charMeasure, const char *c, DialogueLine &textLine, + DialogueTextSection &textSection) { Rectangle resRect = this->textRect; - if (dialogue.lines.at(lineIndex).hasPortrait) { + if (textLine.hasPortrait) { resRect = textPortraitRect; } Vector2 a = Vector2Add(textPos, Vector2{charMeasure.x + 1, 0.0f}); Vector2 finalCharPos = Vector2Add(Vector2{resRect.x, resRect.y}, a); - // Check for text overflow on x axis. - if ((finalCharPos.x + charMeasure.x) > textRect.width) { + auto §ion = dialogue.lines.at(lineIndex).sections.at(sectionIndex); + + bool hasNewline = false; + if (!appliedTag && section.newline) { + hasNewline = true; + } + if (TextIsEqual(c, "\n")) { + hasNewline = true; + } + + // Check for text overflow on x axis or for newline. + if ((finalCharPos.x + charMeasure.x) > textRect.width || hasNewline) { textPos.x = 0; textPos.y += charMeasure.y; @@ -171,19 +261,24 @@ void DialogueBalloon::charP(Vector2 charMeasure, const char *c, Color color) { textPos.x += charMeasure.x; } - DrawTextEx(font, c, finalCharPos, 13 * 3, 1, color); + DrawTextEx(Game::getResources().getFont(textSection.font), c, finalCharPos, textSection.textSize * 3, 1, + textSection.textColor); } void DialogueBalloon::showDialogue(const DialogueBin &newDialogue) { - if (active) - return; + if (active) return; this->dialogue = newDialogue; + this->lineIndex = 0; firstCharTyped = false; active = true; - this->text = newDialogue.lines.at(0).text; + text = ""; + + for (auto k : dialogue.lines.at(lineIndex).sections) { + text = text.append(k.text); + } this->frameCounter = 0; this->charIndex = 0; diff --git a/src/dialogueParser.cpp b/src/dialogueParser.cpp index d268a1fb..306c2273 100644 --- a/src/dialogueParser.cpp +++ b/src/dialogueParser.cpp @@ -2,83 +2,97 @@ #include #include +#include #include #include #include "dialogueBalloon.hpp" +#include "raylib.h" using json = nlohmann::json; -std::vector parseDialogueContent(const std::string &t) { - std::string tagName = ""; - std::string tagContent = ""; - std::string tagClose = ""; - bool parseTag = false; - bool parseTagContent = true; - bool parseTagEnd = false; - bool parseTagClose = false; +std::map textColors = {{"lightgray", LIGHTGRAY}, {"gray", GRAY}, {"darkgray", DARKGRAY}, + {"gold", GOLD}, {"yellow", YELLOW}, {"orange", ORANGE}, + {"pink", PINK}, {"red", RED}, {"maroon", MAROON}, + {"green", GREEN}, {"lime", LIME}, {"darkgreen", DARKGREEN}, + {"skyblue", SKYBLUE}, {"blue", BLUE}, {"darkblue", DARKBLUE}, + {"purple", PURPLE}, {"violet", VIOLET}, {"darkpurple", DARKPURPLE}, + {"beige", BEIGE}, {"brown", BROWN}, {"darkbrown", DARKBROWN}, + {"magenta", MAGENTA}, {"white", WHITE}, {"black", BLACK}}; + +std::map &getColors() { return textColors; } + +std::vector getColorTypes() { + std::vector colorTypes{}; + for (auto const &[key, value] : textColors) { + colorTypes.push_back(key); + } + return colorTypes; +} - std::vector v; - int idx = 0; - for (auto c : t) { - if (c == '<' && !parseTag) { - if (tagName == "") { - v.push_back({"", tagContent}); - tagContent = ""; - } +DialogueTextSection parseSection(pugi::xml_node node, DialogueTextSection base) { + base.key = node.name(); + base.text = node.text().as_string(); - parseTagContent = false; - parseTag = true; - } else if (c == '>') { - parseTagEnd = true; - parseTag = false; - - if (parseTagClose) { - parseTagClose = false; - - if (tagName == tagClose) { - v.push_back({tagName, tagContent}); - - tagName = ""; - tagContent = ""; - tagClose = ""; - parseTag = false; - parseTagContent = true; - parseTagEnd = false; - parseTagClose = false; - } - } - } + printf("%s : %s \n", base.key.c_str(), base.text.c_str()); - if (c == '/') { - parseTag = false; - parseTagClose = true; - } + if (textColors.count(base.key) > 0) { + base.textColor = textColors[base.key]; + } - if (parseTag && c != '<') { - tagName.push_back(c); - } else if (parseTagClose && c != '/') { - tagClose.push_back(c); - } + if (base.key == "textSize") { + base.textSize = node.attribute("size").as_int(16); + } - if (parseTagEnd) { - parseTagContent = true; - parseTagEnd = false; - } + if (base.key == "font") { + base.font = node.attribute("font").as_string("LanaPixel"); + } - if (parseTagContent && c != '>') { - tagContent.push_back(c); + if (base.key == "delay") { + base.delay = node.attribute("delay").as_float(1.0f); + } + + if (base.key == "padding") { + if (!node.attribute("px").empty()) { + base.padding = node.attribute("px").as_float(0.0f); + base.paddingMode = PADDING_PX; } + if (!node.attribute("percent").empty()) { + base.padding = node.attribute("percent").as_int(); + base.paddingMode = PADDING_PERCENT; + } + } - idx++; + if (base.key == "sound") { + base.sound = node.attribute("id").as_string("Text 1"); + } - if (idx == (t.length())) { - v.push_back({"", tagContent}); - tagContent = ""; - } + if (base.key == "nl") { + base.newline = true; } - for (auto item : v) { - printf("%s : %s \n", item.key.c_str(), item.text.c_str()); + return base; +} + +std::vector parseDialogueContent(const std::string &t) { + std::vector v; + + pugi::xml_document xmlDoc; + auto result = xmlDoc.load_string(TextFormat("%s", t.c_str())); + if (result && !xmlDoc.child("text").empty()) { + for (auto item : xmlDoc.child("text").children()) { + DialogueTextSection textSection; + textSection = parseSection(item, textSection); + + if (!item.children().empty()) { + for (auto &subitem : item.children()) { + DialogueTextSection subTextSection; + subTextSection = parseSection(subitem, textSection); + v.push_back(subTextSection); + } + } else { + v.push_back(textSection); + } + } } return v; diff --git a/src/editor/actions/editTileAction.cpp b/src/editor/actions/editTileAction.cpp index ca4a10f9..1eb74b73 100644 --- a/src/editor/actions/editTileAction.cpp +++ b/src/editor/actions/editTileAction.cpp @@ -1,5 +1,6 @@ #include "actions/editTileAction.hpp" + #include "actions/mapAction.hpp" #include "tilemap.hpp" diff --git a/src/editor/actions/eraseTileAction.cpp b/src/editor/actions/eraseTileAction.cpp index c4c48127..0991b7e3 100644 --- a/src/editor/actions/eraseTileAction.cpp +++ b/src/editor/actions/eraseTileAction.cpp @@ -1,5 +1,6 @@ #include "actions/eraseTileAction.hpp" + #include "actions/mapAction.hpp" #include "conversion.hpp" #include "raymath.h" @@ -9,45 +10,43 @@ EraseTileAction::EraseTileAction(MapActionData a) : MapAction(a) {} void EraseTileAction::execute() { switch (data.layer) { - case RoomLayer::LAYER_TILES: { - data.room->getTileMap()->setEmptyTile(data.worldTile); - } break; - case RoomLayer::LAYER_COLLISION: { - auto conv = fromVector2(data.worldTile); - data.room->getCollisions().removeObject(fromVector2(data.worldTile)); - } break; - case RoomLayer::LAYER_INTERACTABLES: { - data.room->getInteractables().removeObject(fromVector2(data.worldTile)); - } break; - case RoomLayer::LAYER_PROPS: { - data.room->getProps().removeObject(fromVector2(data.worldTile)); - } break; - case RoomLayer::LAYER_ACTORS: { - for (auto &&a : data.room->getActors().getActors()) { - if (Vector2Equals(a.second->getTilePosition(), data.worldTile)) { - data.room->getActors().getActors().erase(a.first); - break; + case RoomLayer::LAYER_TILES: { + data.room->getTileMap()->setEmptyTile(data.worldTile); + } break; + case RoomLayer::LAYER_COLLISION: { + auto conv = fromVector2(data.worldTile); + data.room->getCollisions().removeObject(fromVector2(data.worldTile)); + } break; + case RoomLayer::LAYER_INTERACTABLES: { + data.room->getInteractables().removeObject(fromVector2(data.worldTile)); + } break; + case RoomLayer::LAYER_PROPS: { + data.room->getProps().removeObject(fromVector2(data.worldTile)); + } break; + case RoomLayer::LAYER_ACTORS: { + for (auto &&a : data.room->getActors().getActors()) { + if (Vector2Equals(a.second->getTilePosition(), data.worldTile)) { + data.room->getActors().getActors().erase(a.first); + break; + } } - } - } break; - default: - break; + } break; + default: + break; } } void EraseTileAction::undo() { switch (data.layer) { - case RoomLayer::LAYER_TILES: { - data.room->getTileMap()->setTile(data.worldTile, data.prevTile); - } break; - case RoomLayer::LAYER_COLLISION: { - data.room->getCollisions().pushObject(fromVector2(data.worldTile), - false); - } break; - case RoomLayer::LAYER_INTERACTABLES: { - - } break; - default: - break; + case RoomLayer::LAYER_TILES: { + data.room->getTileMap()->setTile(data.worldTile, data.prevTile); + } break; + case RoomLayer::LAYER_COLLISION: { + data.room->getCollisions().pushObject(fromVector2(data.worldTile), false); + } break; + case RoomLayer::LAYER_INTERACTABLES: { + } break; + default: + break; } } diff --git a/src/editor/actions/placeTileAction.cpp b/src/editor/actions/placeTileAction.cpp index 36535dd0..69fb5748 100644 --- a/src/editor/actions/placeTileAction.cpp +++ b/src/editor/actions/placeTileAction.cpp @@ -1,4 +1,8 @@ #include "actions/placeTileAction.hpp" + +#include +#include + #include "actions/mapAction.hpp" #include "actor.hpp" #include "conversion.hpp" @@ -8,98 +12,88 @@ #include "raymath.h" #include "room.hpp" #include "views/worldView.hpp" -#include -#include PlaceTileAction::PlaceTileAction(MapActionData a) : MapAction(a) {} void PlaceTileAction::execute() { switch (data.layer) { - case RoomLayer::LAYER_TILES: { - if (data.room->getTileMap()->getTileSet()->areAtlasCoordsValid( - {static_cast(data.tile.x), - static_cast(data.tile.y)})) { - data.room->getTileMap()->setTile(data.worldTile, data.tile); - } - } break; - case RoomLayer::LAYER_COLLISION: { - auto conv = fromVector2(data.worldTile); - data.room->getCollisions().pushObject(fromVector2(data.worldTile), - false); - } break; - case RoomLayer::LAYER_INTERACTABLES: { - auto inter = data.room->getInteractables().add( - fromVector2(data.worldTile), data.interactable); - if (inter != nullptr) { - char *txt = LoadFileText(data.interactableFullPath.c_str()); - nlohmann::json interJson = json::parse(txt); - UnloadFileText(txt); - inter->setProps(interJson.at("props")); - inter->setOnTouch(interJson.at("onTouch")); - } - } break; - case RoomLayer::LAYER_PROPS: { - auto p = std::make_unique(data.interactableFullPath); - p->setWorldTilePos({data.worldTile.x, data.worldTile.y}, - data.room->getWorldTileSize()); - if (p->getInteractable() != nullptr && p->getHasInteractable()) { - auto interType = p->getInteractable()->getType(); - auto interNames = - Editor::instance->getProject()->getInteractableNames(); - std::string interFileName; - bool found = false; - for (auto [interPath, interName] : interNames) { - std::string fileName = GetFileNameWithoutExt(interPath.c_str()); - if (fileName == interType) { - found = true; - interFileName = interPath; - } + case RoomLayer::LAYER_TILES: { + if (data.room->getTileMap()->getTileSet()->areAtlasCoordsValid( + {static_cast(data.tile.x), static_cast(data.tile.y)})) { + data.room->getTileMap()->setTile(data.worldTile, data.tile); + } + } break; + case RoomLayer::LAYER_COLLISION: { + auto conv = fromVector2(data.worldTile); + data.room->getCollisions().pushObject(fromVector2(data.worldTile), false); + } break; + case RoomLayer::LAYER_INTERACTABLES: { + auto inter = data.room->getInteractables().add(fromVector2(data.worldTile), data.interactable); + if (inter != nullptr) { + char *txt = LoadFileText(data.interactableFullPath.c_str()); + nlohmann::json interJson = json::parse(txt); + UnloadFileText(txt); + inter->setProps(interJson.at("props")); + inter->setOnTouch(interJson.at("onTouch")); } + } break; + case RoomLayer::LAYER_PROPS: { + auto p = std::make_unique(data.interactableFullPath); + p->setWorldTilePos({data.worldTile.x, data.worldTile.y}, data.room->getWorldTileSize()); + if (p->getInteractable() != nullptr && p->getHasInteractable()) { + auto interType = p->getInteractable()->getType(); + auto interNames = Editor::instance->getProject()->getInteractableNames(); + std::string interFileName; + bool found = false; + for (auto [interPath, interName] : interNames) { + std::string fileName = GetFileNameWithoutExt(interPath.c_str()); + if (fileName == interType) { + found = true; + interFileName = interPath; + } + } - char *txt = LoadFileText(interFileName.c_str()); - nlohmann::json propJson = json::parse(txt); - UnloadFileText(txt); - p->getInteractable()->setProps(propJson.at("props")); - } - // data.room->addProp(std::move(p)); - data.room->getProps().pushObject(fromVector2(data.worldTile), - std::move(p)); - } break; - case RoomLayer::LAYER_ACTORS: { - auto a = std::make_unique(data.interactableFullPath); - a->setTilePosition( - data.worldTile, - data.room->getTileMap()->getTileSet()->getTileSize()); - data.room->getActors().getActors()[data.actorName] = std::move(a); - } break; - default: - break; + char *txt = LoadFileText(interFileName.c_str()); + nlohmann::json propJson = json::parse(txt); + UnloadFileText(txt); + p->getInteractable()->setProps(propJson.at("props")); + } + // data.room->addProp(std::move(p)); + data.room->getProps().pushObject(fromVector2(data.worldTile), std::move(p)); + } break; + case RoomLayer::LAYER_ACTORS: { + auto a = std::make_unique(data.interactableFullPath); + a->setTilePosition(data.worldTile, data.room->getTileMap()->getTileSet()->getTileSize()); + data.room->getActors().getActors()[data.actorName] = std::move(a); + } break; + default: + break; } } void PlaceTileAction::undo() { switch (data.layer) { - case RoomLayer::LAYER_TILES: { - data.room->getTileMap()->setTile(data.worldTile, data.prevTile); - } break; - case RoomLayer::LAYER_COLLISION: { - data.room->getCollisions().removeObject(fromVector2(data.worldTile)); - } break; - case RoomLayer::LAYER_INTERACTABLES: { - data.room->getInteractables().removeObject(fromVector2(data.worldTile)); - } break; - case RoomLayer::LAYER_PROPS: { - data.room->getProps().removeObject(fromVector2(data.worldTile)); - } break; - case RoomLayer::LAYER_ACTORS: { - for (auto &&a : data.room->getActors().getActors()) { - if (Vector2Equals(a.second->getTilePosition(), data.worldTile)) { - data.room->getActors().getActors().erase(a.first); - break; + case RoomLayer::LAYER_TILES: { + data.room->getTileMap()->setTile(data.worldTile, data.prevTile); + } break; + case RoomLayer::LAYER_COLLISION: { + data.room->getCollisions().removeObject(fromVector2(data.worldTile)); + } break; + case RoomLayer::LAYER_INTERACTABLES: { + data.room->getInteractables().removeObject(fromVector2(data.worldTile)); + } break; + case RoomLayer::LAYER_PROPS: { + data.room->getProps().removeObject(fromVector2(data.worldTile)); + } break; + case RoomLayer::LAYER_ACTORS: { + for (auto &&a : data.room->getActors().getActors()) { + if (Vector2Equals(a.second->getTilePosition(), data.worldTile)) { + data.room->getActors().getActors().erase(a.first); + break; + } } - } - } break; - default: - break; + } break; + default: + break; } } diff --git a/src/editor/actions/startPointAction.cpp b/src/editor/actions/startPointAction.cpp index 083a99fb..d4e36c37 100644 --- a/src/editor/actions/startPointAction.cpp +++ b/src/editor/actions/startPointAction.cpp @@ -1,4 +1,5 @@ #include "actions/startPointAction.hpp" + #include "actions/mapAction.hpp" StartPointAction::StartPointAction(MapActionData data) : MapAction(data) {} diff --git a/src/editor/childWindows/aboutWindow.cpp b/src/editor/childWindows/aboutWindow.cpp index 5db90cf2..7c1fb70e 100644 --- a/src/editor/childWindows/aboutWindow.cpp +++ b/src/editor/childWindows/aboutWindow.cpp @@ -1,4 +1,7 @@ #include "childWindows/aboutWindow.hpp" + +#include + #include "TGUI/Config.hpp" #include "TGUI/Layout.hpp" #include "TGUI/Widgets/ChildWindow.hpp" @@ -7,7 +10,6 @@ #include "bindTranslation.hpp" #include "childWindows/popupWindow.hpp" #include "editor.hpp" -#include AboutWindow::AboutWindow() : PopupWindow("AboutWindow") { auto layout = tgui::GrowVerticalLayout::create(); @@ -16,10 +18,8 @@ AboutWindow::AboutWindow() : PopupWindow("AboutWindow") { EditorGuiService::createLogoCenter(layout); auto infoText = tgui::Label::create(); - bindTranslation(infoText, "menu.about.rpgpp_description", - &tgui::Label::setText); - bindTranslation(this->currentWindow, "menu.about._label", - &tgui::ChildWindow::setTitle); + bindTranslation(infoText, "menu.about.rpgpp_description", &tgui::Label::setText); + bindTranslation(this->currentWindow, "menu.about._label", &tgui::ChildWindow::setTitle); infoText->setTextSize(20); infoText->setHorizontalAlignment(tgui::HorizontalAlignment::Center); layout->add(infoText); diff --git a/src/editor/childWindows/addDelayDialogueWindow.cpp b/src/editor/childWindows/addDelayDialogueWindow.cpp new file mode 100644 index 00000000..e8dec65b --- /dev/null +++ b/src/editor/childWindows/addDelayDialogueWindow.cpp @@ -0,0 +1,53 @@ +#include "childWindows/addDelayDialogueWindow.hpp" + +#include +#include + +#include "TGUI/Layout.hpp" +#include "TGUI/Widgets/Button.hpp" +#include "TGUI/Widgets/ChildWindow.hpp" +#include "TGUI/Widgets/GrowVerticalLayout.hpp" +#include "TGUI/Widgets/Label.hpp" +#include "TGUI/Widgets/SpinControl.hpp" +#include "bindTranslation.hpp" +#include "childWindows/popupWindow.hpp" + +AddDelayDialogueWindow::AddDelayDialogueWindow() : PopupWindow("Add Delay...") { + this->editor = nullptr; + bindTranslation(this->currentWindow, "dialog.delaywindow.add_a_delay", + &tgui::ChildWindow::setTitle); + + this->currentWindow->setSize(400, 150); + + auto verticalLayout = tgui::GrowVerticalLayout::create(); + verticalLayout->setOrigin({0.5, 0.5}); + verticalLayout->setPosition({"50%", "50%"}); + verticalLayout->getRenderer()->setPadding(5.0f); + + auto descriptionLabel = tgui::Label::create(); + descriptionLabel->setHorizontalAlignment(tgui::HorizontalAlignment::Center); + bindTranslation(descriptionLabel, "dialog.delaywindow.description", &tgui::Label::setText); + verticalLayout->add(descriptionLabel); + + // Allow for more precise second editing. + this->delaySpin = tgui::SpinControl::create(); + delaySpin->setSize({"100%", 32}); + delaySpin->setStep(0.1); + delaySpin->setDecimalPlaces(3); + verticalLayout->add(this->delaySpin); + + auto confirmButton = tgui::Button::create(); + bindTranslation(confirmButton, "dialog.delaywindow.confirm", &tgui::Button::setText); + confirmButton->onPress.connect([this] { + this->editor->addXmlTagWithProperties("delay", {{"delay", std::to_string(delaySpin->getValue())}}); + this->currentWindow->close(); + }); + verticalLayout->add(confirmButton); + + currentWindow->add(verticalLayout); +} + +void AddDelayDialogueWindow::open(std::shared_ptr editor) { + this->editor = editor; + PopupWindow::open(); +} diff --git a/src/editor/childWindows/addDialogueOptionWindow.cpp b/src/editor/childWindows/addDialogueOptionWindow.cpp new file mode 100644 index 00000000..d7505f0c --- /dev/null +++ b/src/editor/childWindows/addDialogueOptionWindow.cpp @@ -0,0 +1,70 @@ +#include "childWindows/addDialogueOptionWindow.hpp" + +#include + +#include "TGUI/Widgets/Button.hpp" +#include "TGUI/Widgets/Panel.hpp" +#include "bindTranslation.hpp" +#include "childWindows/popupWindow.hpp" +#include "widgets/propertyFields/fileField.hpp" +#include "widgets/propertyFields/textField.hpp" + +AddDialogueOptionWindow::AddDialogueOptionWindow() : PopupWindow("Add Dialogue Option..") { + bindTranslation(this->currentWindow, "dialog.add_dialogue_option.title", &tgui::ChildWindow::setTitle); + + dialogue = nullptr; + lineIndex = 0; + fileView = nullptr; + + currentWindow->setSize(280, 180); + + auto panel = tgui::Panel::create(); + panel->getRenderer()->setPadding({4, 4}); + + auto layout = tgui::GrowVerticalLayout::create(); + layout->getRenderer()->setSpaceBetweenWidgets(4); + panel->add(layout); + + auto nameField = TextField::create(); + nameField->setSize({"100%", 24}); + bindTranslation(nameField->label, "dialog.add_dialogue_option.name", &tgui::Label::setText); + layout->add(nameField); + + auto dialogueField = FileField::create(); + dialogueField->setSize({"100%", 24}); + bindTranslation(dialogueField->label, "dialog.add_dialogue_option.dialogue", &tgui::Label::setText); + dialogueField->pathFilters = {{"RPG++ Dialogue", {"*.rdiag"}}}; + layout->add(dialogueField); + + auto confirmButton = tgui::Button::create(); + bindTranslation(confirmButton, "dialog.add_dialogue_option.submit", &tgui::Button::setText); + confirmButton->setSize({"100%", 24}); + + std::weak_ptr weakName = nameField; + std::weak_ptr weakDialogue = dialogueField; + confirmButton->onClick([weakName, weakDialogue, this] { + if (weakName.expired() || weakDialogue.expired()) return; + + auto nameShared = weakName.lock(); + auto dialogueShared = weakDialogue.lock(); + + auto nameText = nameShared->value->getText().toStdString(); + + if (!nameText.empty() && !dialogueShared->value->getText().empty()) { + dialogue->getData().lines[lineIndex].hasOptions = true; + dialogue->getData().lines[lineIndex].options.push_back( + {nameText, dialogueShared->value->getText().toStdString()}); + + nameShared->value->setText(""); + dialogueShared->value->setText(""); + + fileView->initOptionPanel(lineIndex); + + close(); + } + }); + + layout->add(confirmButton); + + currentWindow->add(panel); +} diff --git a/src/editor/childWindows/colorSelectWindow.cpp b/src/editor/childWindows/colorSelectWindow.cpp new file mode 100644 index 00000000..560bb6e6 --- /dev/null +++ b/src/editor/childWindows/colorSelectWindow.cpp @@ -0,0 +1,74 @@ +#include "childWindows/colorSelectWindow.hpp" + +#include +#include +#include +#include + +#include "TGUI/Color.hpp" +#include "TGUI/Cursor.hpp" +#include "TGUI/Layout.hpp" +#include "TGUI/Widgets/Button.hpp" +#include "TGUI/Widgets/ChildWindow.hpp" +#include "TGUI/Widgets/GrowVerticalLayout.hpp" +#include "TGUI/Widgets/ScrollablePanel.hpp" +#include "bindTranslation.hpp" +#include "childWindows/popupWindow.hpp" +#include "dialogueParser.hpp" +#include "raylib.h" +#include "widgets/dialogueEditor.hpp" + +constexpr int BLACK_WHITE_THRESHOLD = 80; + +ColorSelectWindow::ColorSelectWindow() : PopupWindow("Select a Color") { + this->editor = nullptr; + + bindTranslation(this->currentWindow, "screen.project.dialogueview.select_a_color", + &tgui::ChildWindow::setTitle); + auto scrollablePanel = tgui::ScrollablePanel::create(); + auto verticalLayout = tgui::GrowVerticalLayout::create(); + verticalLayout->getRenderer()->setPadding(5.0f); + + std::vector types = getColorTypes(); + std::map colors = getColors(); + for (int i = 0; i < types.size(); i++) { + auto type = types[i]; + + auto colorButton = tgui::Button::create(); + colorButton->setMouseCursor(tgui::Cursor::Type::Hand); + + bindTranslation(colorButton, TextFormat("screen.project.dialogueview.color.%s", type.c_str()), + &tgui::Button::setText); + + colorButton->setSize({"100%", 30}); + + Color color = colors[types[i]]; + tgui::Color btnBackColor = {color.r, color.g, color.b, color.a}; + + // Set the color of the background of the color picker. + auto btnRenderer = colorButton->getRenderer(); + btnRenderer->setBackgroundColor(btnBackColor); + btnRenderer->setBackgroundColorHover(btnBackColor); + + bool displayAsBlack = ((color.r + color.g + color.b) / 3.0f) > BLACK_WHITE_THRESHOLD; + auto textColor = displayAsBlack ? tgui::Color::Black : tgui::Color::White; + + btnRenderer->setTextColor(textColor); + btnRenderer->setTextColorHover(textColor); + + colorButton->onPress.connect([this, type] { + this->editor->addXmlTag(type); + this->close(); + }); + + verticalLayout->add(colorButton); + } + + scrollablePanel->add(verticalLayout); + this->currentWindow->add(scrollablePanel); +} + +void ColorSelectWindow::open(std::shared_ptr editor) { + PopupWindow::open(); + this->editor = editor; +} diff --git a/src/editor/childWindows/editDialogueOptionWindow.cpp b/src/editor/childWindows/editDialogueOptionWindow.cpp new file mode 100644 index 00000000..f6d4415b --- /dev/null +++ b/src/editor/childWindows/editDialogueOptionWindow.cpp @@ -0,0 +1,87 @@ +#include "childWindows/editDialogueOptionWindow.hpp" + +#include "TGUI/Widgets/Button.hpp" +#include "bindTranslation.hpp" +#include "childWindows/popupWindow.hpp" + +EditDialogueOptionWindow::EditDialogueOptionWindow() : PopupWindow("Edit a Dialogue Option..") { + bindTranslation(this->currentWindow, "dialog.edit_dialogue_option.title", &tgui::ChildWindow::setTitle); + + dialogue = nullptr; + lineIndex = 0; + fileView = nullptr; + optionIndex = 0; + + currentWindow->setSize(280, 180); + + auto panel = tgui::Panel::create(); + panel->getRenderer()->setPadding({4, 4}); + + auto layout = tgui::GrowVerticalLayout::create(); + layout->getRenderer()->setSpaceBetweenWidgets(4); + panel->add(layout); + + nameField = TextField::create(); + nameField->setSize({"100%", 24}); + bindTranslation(nameField->label, "dialog.edit_dialogue_option.name", &tgui::Label::setText); + layout->add(nameField); + + dialogueField = FileField::create(); + dialogueField->setSize({"100%", 24}); + bindTranslation(dialogueField->label, "dialog.edit_dialogue_option.dialogue", &tgui::Label::setText); + dialogueField->pathFilters = {{"RPG++ Dialogue", {"*.rdiag"}}}; + layout->add(dialogueField); + + auto confirmButton = tgui::Button::create(); + bindTranslation(confirmButton, "dialog.edit_dialogue_option.submit", &tgui::Button::setText); + confirmButton->setSize({"100%", 24}); + + std::weak_ptr weakName = nameField; + std::weak_ptr weakDialogue = dialogueField; + confirmButton->onClick([weakName, weakDialogue, this] { + if (weakName.expired() || weakDialogue.expired()) return; + + auto nameShared = weakName.lock(); + auto dialogueShared = weakDialogue.lock(); + + auto nameText = nameShared->value->getText().toStdString(); + + auto &line = dialogue->getData().lines.at(lineIndex); + auto &option = line.options.at(optionIndex); + + option.title = nameText; + option.nextDialogue = dialogueShared->value->getText().toStdString(); + + fileView->initOptionPanel(lineIndex); + + close(); + }); + layout->add(confirmButton); + + auto removeButton = tgui::Button::create(); + bindTranslation(removeButton, "dialog.edit_dialogue_option.remove", &tgui::Button::setText); + removeButton->setSize({"100%", 24}); + removeButton->onClick([this] { + auto &line = dialogue->getData().lines.at(lineIndex); + line.options.erase(line.options.begin() + optionIndex); + + fileView->initOptionPanel(lineIndex); + + close(); + }); + layout->add(removeButton); + + currentWindow->add(panel); +} + +void EditDialogueOptionWindow::setup(Dialogue *dialogue, int lineIndex, int optionIndex) { + this->dialogue = dialogue; + this->lineIndex = lineIndex; + this->optionIndex = optionIndex; + + auto &line = dialogue->getData().lines.at(lineIndex); + auto &option = line.options.at(optionIndex); + + nameField->value->setText(option.title); + dialogueField->value->setText(option.nextDialogue); +} \ No newline at end of file diff --git a/src/editor/childWindows/editPropWindow.cpp b/src/editor/childWindows/editPropWindow.cpp new file mode 100644 index 00000000..5a6c11a2 --- /dev/null +++ b/src/editor/childWindows/editPropWindow.cpp @@ -0,0 +1,83 @@ +#include "childWindows/editPropWindow.hpp" + +#include + +#include "TGUI/Widgets/Button.hpp" +#include "TGUI/Widgets/ComboBox.hpp" +#include "TGUI/Widgets/GrowVerticalLayout.hpp" +#include "TGUI/Widgets/Label.hpp" +#include "TGUI/Widgets/Panel.hpp" +#include "bindTranslation.hpp" +#include "childWindows/newPropWindow.hpp" +#include "childWindows/popupWindow.hpp" +#include "nlohmann/json.hpp" +#include "nlohmann/json_fwd.hpp" +#include "widgets/propertyFields/selectField.hpp" + +EditPropWindow::EditPropWindow() : PopupWindow("Edit Prop..") { + bindTranslation(this->currentWindow, "dialog.edit_prop.title", &tgui::ChildWindow::setTitle); + props = nullptr; + currentWindow->setSize(280, 180); + + auto panel = tgui::Panel::create(); + panel->getRenderer()->setPadding({4, 4}); + + auto layout = tgui::GrowVerticalLayout::create(); + layout->getRenderer()->setSpaceBetweenWidgets(4); + panel->add(layout); + + nameLabel = tgui::Label::create(); + nameLabel->setSize({"100%", 24}); + nameLabel->setText(propName); + layout->add(nameLabel); + + dropdown = SelectField::create(); + dropdown->setSize({"100%", 24}); + bindTranslation(dropdown->label, "dialog.edit_prop.type", &tgui::Label::setText); + dropdown->value->addMultipleItems({"integer", "string", "boolean", "dialogue"}); + dropdown->value->setSelectedItemByIndex(0); + layout->add(dropdown); + + auto confirmButton = tgui::Button::create(); + bindTranslation(confirmButton, "dialog.edit_prop.submit", &tgui::Button::setText); + confirmButton->setSize({"100%", 24}); + + std::weak_ptr weakDropdown = dropdown; + confirmButton->onClick([this, weakDropdown] { + if (weakDropdown.expired()) { + return; + } + + auto dropdownShared = weakDropdown.lock(); + + std::string nameText = propName; + + if (interactable != nullptr) { + int idx = dropdownShared->value->getSelectedItemIndex(); + PropType propType = static_cast(idx); + + interactable->getProps().erase(nameText); + + interactable->addProp(propType, nameText); + + box->addPropsJson(interactable->getProps(), true, true); + close(); + } + }); + layout->add(confirmButton); + + auto removeButton = tgui::Button::create(); + bindTranslation(removeButton, "dialog.edit_prop.remove", &tgui::Button::setText); + removeButton->setSize({"100%", 24}); + removeButton->onClick([this] { + if (interactable != nullptr) { + interactable->getProps().erase(propName); + + box->addPropsJson(*interactable->getPropsPtr(), true, true); + close(); + } + }); + layout->add(removeButton); + + currentWindow->add(panel); +} diff --git a/src/editor/childWindows/newPropWindow.cpp b/src/editor/childWindows/newPropWindow.cpp new file mode 100644 index 00000000..12ac1737 --- /dev/null +++ b/src/editor/childWindows/newPropWindow.cpp @@ -0,0 +1,72 @@ +#include "childWindows/newPropWindow.hpp" + +#include + +#include "TGUI/Widgets/Button.hpp" +#include "TGUI/Widgets/ComboBox.hpp" +#include "TGUI/Widgets/GrowVerticalLayout.hpp" +#include "TGUI/Widgets/Panel.hpp" +#include "bindTranslation.hpp" +#include "childWindows/popupWindow.hpp" +#include "nlohmann/json.hpp" +#include "nlohmann/json_fwd.hpp" +#include "widgets/propertyFields/selectField.hpp" +#include "widgets/propertyFields/textField.hpp" + +NewPropWindow::NewPropWindow() : PopupWindow("New Prop..") { + bindTranslation(this->currentWindow, "dialog.new_prop.title", &tgui::ChildWindow::setTitle); + props = nullptr; + currentWindow->setSize(280, 180); + + auto panel = tgui::Panel::create(); + panel->getRenderer()->setPadding({4, 4}); + + auto layout = tgui::GrowVerticalLayout::create(); + layout->getRenderer()->setSpaceBetweenWidgets(4); + panel->add(layout); + + auto nameField = TextField::create(); + nameField->setSize({"100%", 24}); + bindTranslation(nameField->label, "dialog.new_prop.name", &tgui::Label::setText); + layout->add(nameField); + + auto dropdownField = SelectField::create(); + dropdownField->setSize({"100%", 24}); + bindTranslation(dropdownField->label, "dialog.new_prop.type", &tgui::Label::setText); + dropdownField->value->addMultipleItems({"integer", "string", "boolean", "dialogue"}); + dropdownField->value->setSelectedItemByIndex(0); + layout->add(dropdownField); + + auto confirmButton = tgui::Button::create(); + bindTranslation(confirmButton, "dialog.new_prop.submit", &tgui::Button::setText); + confirmButton->setSize({"100%", 24}); + + std::weak_ptr weakName = nameField; + std::weak_ptr weakDropdown = dropdownField; + confirmButton->onClick([this, weakName, weakDropdown] { + if (weakName.expired() || weakDropdown.expired()) { + return; + } + + auto nameShared = weakName.lock(); + auto dropdownShared = weakDropdown.lock(); + + auto nameText = nameShared->value->getText().toStdString(); + + if (interactable != nullptr && !nameText.empty()) { + int idx = dropdownShared->value->getSelectedItemIndex(); + PropType propType = static_cast(idx); + + interactable->addProp(propType, nameText); + + box->addPropsJson(interactable->getProps(), true, true); + close(); + } + + nameShared->value->setText(""); + dropdownShared->value->setSelectedItemByIndex(0); + }); + layout->add(confirmButton); + + currentWindow->add(panel); +} diff --git a/src/editor/childWindows/popupWindow.cpp b/src/editor/childWindows/popupWindow.cpp index 26a23f4f..c7174a1e 100644 --- a/src/editor/childWindows/popupWindow.cpp +++ b/src/editor/childWindows/popupWindow.cpp @@ -1,11 +1,13 @@ #include "childWindows/popupWindow.hpp" + +#include + #include "TGUI/Animation.hpp" #include "TGUI/Backend/raylib.hpp" #include "TGUI/Duration.hpp" #include "TGUI/Widgets/ChildWindow.hpp" #include "editor.hpp" #include "services/editorGuiService.hpp" -#include constexpr const int ANIMATION_DURATION = 200; constexpr const float TITLEBAR_HEIGHT = 30.0f; @@ -13,8 +15,7 @@ constexpr tgui::ShowEffectType ANIMATION_TYPE = tgui::ShowEffectType::Scale; PopupWindow::PopupWindow(const std::string &title) { this->currentWindow = tgui::ChildWindow::create(title); - this->currentWindow->onClose.connect( - [this] { this->windowIsOpen = false; }); + this->currentWindow->onClose.connect([this] { this->windowIsOpen = false; }); this->currentWindow->onClosing.connect([this](bool *abort) { *abort = true; this->close(); @@ -22,25 +23,22 @@ PopupWindow::PopupWindow(const std::string &title) { } void PopupWindow::open() { - if (this->windowIsOpen) - return; + if (this->windowIsOpen) return; std::unique_ptr &gui = Editor::instance->getGui().gui; - if (gui->getWidgetIndex(this->currentWindow) == -1) - gui->add(this->currentWindow); + if (gui->getWidgetIndex(this->currentWindow) == -1) gui->add(this->currentWindow); // pop-up in the center of the screen. this->currentWindow->setPosition("(parent.innersize - size) / 2"); ; - this->currentWindow->showWithEffect(ANIMATION_TYPE, - tgui::Duration(ANIMATION_DURATION)); + this->currentWindow->showWithEffect(ANIMATION_TYPE, tgui::Duration(ANIMATION_DURATION)); this->windowIsOpen = true; + this->currentWindow->moveToFront(); } void PopupWindow::close() { - if (!this->windowIsOpen) - return; + if (!this->windowIsOpen) return; this->currentWindow->hideWithEffect(ANIMATION_TYPE, ANIMATION_DURATION); this->windowIsOpen = false; diff --git a/src/editor/childWindows/projectSettingsPanel/game.cpp b/src/editor/childWindows/projectSettingsPanel/game.cpp new file mode 100644 index 00000000..210dd50f --- /dev/null +++ b/src/editor/childWindows/projectSettingsPanel/game.cpp @@ -0,0 +1,132 @@ +#include "childWindows/projectSettingsPanel/game.hpp" + +#include + +#include "TGUI/String.hpp" +#include "TGUI/Widgets/GrowVerticalLayout.hpp" +#include "TGUI/Widgets/Label.hpp" +#include "TGUI/Widgets/ScrollablePanel.hpp" +#include "childWindows/editListFieldWindow.hpp" +#include "childWindows/settingsPanel/base.hpp" +#include "editor.hpp" +#include "listHelper.hpp" +#include "project.hpp" +#include "raylib.h" +#include "widgets/propertyFields/boolField.hpp" +#include "widgets/propertyFields/fileField.hpp" +#include "widgets/propertyFields/intField.hpp" +#include "widgets/propertyFields/listField.hpp" + +ProjectSettingsPanelGame::ProjectSettingsPanelGame(tgui::TabContainer::Ptr tabContainer) + : SettingsPanelBase(tabContainer, "dialog.project_settings.game._label") { + const tgui::ScrollablePanel::Ptr scrollPanel = tgui::ScrollablePanel::create(); + scrollPanel->setSize("100%", "100%"); + scrollPanel->getRenderer()->setPadding(4); + + editListFieldWindow = std::make_unique>(); + + const auto layout = tgui::GrowVerticalLayout::create(); + layout->setSize("80%", "100%"); + layout->setPosition({"50%", "0%"}); + layout->setOrigin({0.5, 0}); + layout->getRenderer()->setSpaceBetweenWidgets(10.0f); + + defaultRoom = FileField::create(); + bindTranslation(defaultRoom->label, "dialog.project_settings.game.default_room", &tgui::Label::setText); + defaultRoom->setSize({"100%", 24}); + defaultRoom->pathFilters = {{"RPG++ Room", {"*.rmap"}}}; + defaultRoom->callback = [](const tgui::String &path) { + Project *project = Editor::instance->getProject(); + if (project != nullptr) { + project->getGameSettings().defaultRoomPath = TextFormat("maps/%s", GetFileName(path.toStdString().c_str())); + } + }; + + playerActor = FileField::create(); + bindTranslation(playerActor->label, "dialog.project_settings.game.player_actor", &tgui::Label::setText); + playerActor->setSize({"100%", 24}); + playerActor->pathFilters = {{"RPG++ Actor", {"*.ractor"}}}; + playerActor->label->setText("Player Actor"); + playerActor->callback = [](const tgui::String &path) { + Project *project = Editor::instance->getProject(); + if (project != nullptr) { + project->getGameSettings().playerActorPath = + TextFormat("actors/%s", GetFileName(path.toStdString().c_str())); + } + }; + + tileSize = IntField::create(); + bindTranslation(tileSize->label, "dialog.project_settings.game.tile_size", &tgui::Label::setText); + tileSize->setSize({"100%", 24}); + tileSize->label->setText("Tile Size"); + tileSize->value->setMinimum(16); + tileSize->value->setMaximum(64); + tileSize->value->onValueChange([](int value) { + Project *project = Editor::instance->getProject(); + if (project != nullptr) { + project->getGameSettings().tileSize = value; + } + }); + + debugDraw = BoolField::create(); + bindTranslation(debugDraw->label, "dialog.project_settings.game.debug_draw", &tgui::Label::setText); + debugDraw->label->setText("Debug Draw"); + debugDraw->setSize({"100%", 24}); + debugDraw->value->onCheck([](bool value) { + Project *project = Editor::instance->getProject(); + if (project != nullptr) { + project->getGameSettings().debugDraw = value; + } + }); + + exportImageScales = ListField::create(); + bindTranslation(exportImageScales->label, "dialog.project_settings.game.export_image_scales", + &tgui::Label::setText); + exportImageScales->label->setText("Export Image Scales"); + exportImageScales->setSize({"100%", 24}); + exportImageScales->value->onPress([this] { + Project *project = Editor::instance->getProject(); + + if (project != nullptr) { + editListFieldWindow->field = exportImageScales.get(); + editListFieldWindow->setup(&project->getGameSettings().exportImageScales); + editListFieldWindow->open(); + } + }); + + exportFontSizes = ListField::create(); + bindTranslation(exportFontSizes->label, "dialog.project_settings.game.export_font_sizes", &tgui::Label::setText); + exportFontSizes->label->setText("Export Font Sizes"); + exportFontSizes->setSize({"100%", 24}); + exportFontSizes->value->onPress([this] { + Project *project = Editor::instance->getProject(); + + if (project != nullptr) { + editListFieldWindow->field = exportFontSizes.get(); + editListFieldWindow->setup(&project->getGameSettings().exportFontSizes); + editListFieldWindow->open(); + } + }); + + layout->add(defaultRoom); + layout->add(playerActor); + layout->add(tileSize); + layout->add(debugDraw); + layout->add(exportImageScales); + layout->add(exportFontSizes); + + scrollPanel->add(layout); + panel->add(scrollPanel); +} + +void ProjectSettingsPanelGame::setup(Project *project) { + if (project == nullptr) return; + + auto &gameSet = project->getGameSettings(); + + defaultRoom->value->setText(GetFileName(gameSet.defaultRoomPath.c_str())); + playerActor->value->setText(GetFileName(gameSet.playerActorPath.c_str())); + tileSize->value->setValue(gameSet.tileSize); + exportImageScales->value->setText(VecToString(gameSet.exportImageScales)); + exportFontSizes->value->setText(VecToString(gameSet.exportFontSizes)); +} \ No newline at end of file diff --git a/src/editor/childWindows/projectSettingsPanel/program.cpp b/src/editor/childWindows/projectSettingsPanel/program.cpp new file mode 100644 index 00000000..1560a670 --- /dev/null +++ b/src/editor/childWindows/projectSettingsPanel/program.cpp @@ -0,0 +1,154 @@ +#include "childWindows/projectSettingsPanel/program.hpp" + +#include "TGUI/String.hpp" +#include "TGUI/Widgets/GrowVerticalLayout.hpp" +#include "TGUI/Widgets/ScrollablePanel.hpp" +#include "childWindows/settingsPanel/base.hpp" +#include "project.hpp" +#include "raylib.h" +#include "widgets/propertyFields/boolField.hpp" +#include "widgets/propertyFields/fileField.hpp" +#include "widgets/propertyFields/intField.hpp" +#include "widgets/propertyFields/textField.hpp" + +ProjectSettingsPanelProgram::ProjectSettingsPanelProgram(tgui::TabContainer::Ptr tabContainer) + : SettingsPanelBase(tabContainer, "dialog.project_settings.program._label") { + const tgui::ScrollablePanel::Ptr scrollPanel = tgui::ScrollablePanel::create(); + scrollPanel->setSize("100%", "100%"); + scrollPanel->getRenderer()->setPadding(4); + + const auto layout = tgui::GrowVerticalLayout::create(); + layout->setSize("80%", "100%"); + layout->setPosition({"50%", "0%"}); + layout->setOrigin({0.5, 0}); + layout->getRenderer()->setSpaceBetweenWidgets(10.0f); + + titleField = TextField::create(); + bindTranslation(titleField->label, "dialog.project_settings.program.title", &tgui::Label::setText); + titleField->setSize({"100%", 24}); + titleField->value->onTextChange([](const tgui::String &text) { + Project *project = Editor::instance->getProject(); + if (project != nullptr) { + project->getProgramSettings().projectTitle = text.toStdString(); + } + }); + + versionField = TextField::create(); + bindTranslation(versionField->label, "dialog.project_settings.program.version", &tgui::Label::setText); + versionField->setSize({"100%", 24}); + versionField->value->onTextChange([](const tgui::String &text) { + Project *project = Editor::instance->getProject(); + if (project != nullptr) { + project->getProgramSettings().projectVersion = text.toStdString(); + } + }); + + programIcon = FileField::create(); + programIcon->setSize({"100%", 24}); + programIcon->pathFilters = {{"Image", {"*.png", "*.jpg"}}}; + bindTranslation(programIcon->label, "dialog.project_settings.program.program_icon", &tgui::Label::setText); + programIcon->callback = [](const tgui::String &path) { + Project *project = Editor::instance->getProject(); + if (project != nullptr) { + project->getProgramSettings().programIconPath = + TextFormat("images/%s", GetFileName(path.toStdString().c_str())); + } + }; + + windowSizeX = IntField::create(); + windowSizeX->setSize({"100%", 24}); + bindTranslation(windowSizeX->label, "dialog.project_settings.program.window_width", &tgui::Label::setText); + windowSizeX->value->setMinimum(640); + windowSizeX->value->setMaximum(1920); + windowSizeX->value->onValueChange([](int value) { + Project *project = Editor::instance->getProject(); + if (project != nullptr) { + auto windowSize = project->getProgramSettings().windowSize; + windowSize.x = value; + project->getProgramSettings().windowSize = windowSize; + } + }); + + windowSizeY = IntField::create(); + windowSizeY->setSize({"100%", 24}); + bindTranslation(windowSizeY->label, "dialog.project_settings.program.window_height", &tgui::Label::setText); + windowSizeY->value->setMinimum(480); + windowSizeY->value->setMaximum(1080); + windowSizeY->value->onValueChange([](int value) { + Project *project = Editor::instance->getProject(); + if (project != nullptr) { + auto windowSize = project->getProgramSettings().windowSize; + windowSize.y = value; + project->getProgramSettings().windowSize = windowSize; + } + }); + + resizeable = BoolField::create(); + resizeable->setSize({"100%", 24}); + bindTranslation(resizeable->label, "dialog.project_settings.program.is_resizable", &tgui::Label::setText); + resizeable->value->onChange([](bool value) { + Project *project = Editor::instance->getProject(); + project->getProgramSettings().windowResizeableFlag = value; + }); + + windowStateFlag = SelectField::create(); + windowStateFlag->setSize({"100%", 24}); + bindTranslation(windowStateFlag->label, "dialog.project_settings.program.window_mode", &tgui::Label::setText); + for (auto &[k, v] : WindowStateToName) { + windowStateFlag->value->addItem(v); + } + windowStateFlag->value->onItemSelect([](const tgui::String &text) { + Project *project = Editor::instance->getProject(); + if (project != nullptr) { + for (auto &[k, v] : WindowStateToName) { + if (v == text) { + project->getProgramSettings().windowStateFlag = k; + break; + } + } + } + }); + + targetFPS = IntField::create(); + targetFPS->setSize({"100%", 24}); + bindTranslation(targetFPS->label, "dialog.project_settings.program.target_fps", &tgui::Label::setText); + targetFPS->value->setMinimum(0); + targetFPS->value->setMaximum(1000); + targetFPS->value->onValueChange([](int value) { + Project *project = Editor::instance->getProject(); + if (project != nullptr) { + project->getProgramSettings().targetFPS = value; + } + }); + + layout->add(titleField); + layout->add(programIcon); + layout->add(versionField); + layout->add(windowSizeX); + layout->add(windowSizeY); + layout->add(resizeable); + layout->add(windowStateFlag); + layout->add(targetFPS); + + scrollPanel->add(layout); + panel->add(scrollPanel); +} + +void ProjectSettingsPanelProgram::setup(Project *project) { + if (project == nullptr) return; + + auto &programSet = project->getProgramSettings(); + + titleField->value->setText(programSet.projectTitle); + if (!programSet.programIconPath.empty()) { + programIcon->value->setText(GetFileName(programSet.programIconPath.c_str())); + } + + versionField->value->setText(programSet.projectVersion); + windowSizeX->value->setValue(programSet.windowSize.x); + windowSizeY->value->setValue(programSet.windowSize.y); + + resizeable->value->setChecked(programSet.windowResizeableFlag); + windowStateFlag->value->setSelectedItem(WindowStateToName.at(programSet.windowStateFlag)); + targetFPS->value->setValue(programSet.targetFPS); +} diff --git a/src/editor/childWindows/projectSettingsWindow.cpp b/src/editor/childWindows/projectSettingsWindow.cpp new file mode 100644 index 00000000..ff0e2038 --- /dev/null +++ b/src/editor/childWindows/projectSettingsWindow.cpp @@ -0,0 +1,52 @@ +#include "childWindows/projectSettingsWindow.hpp" + +#include + +#include "TGUI/Widgets/Button.hpp" +#include "childWindows/popupWindow.hpp" +#include "childWindows/projectSettingsPanel/game.hpp" +#include "childWindows/projectSettingsPanel/program.hpp" +#include "childWindows/settingsPanel/base.hpp" +#include "editor.hpp" +#include "project.hpp" +#include "raylib.h" + +ProjectSettingsWindow::ProjectSettingsWindow() : PopupWindow("ProjectSettings") { + tgui::TabContainer::Ptr tabContainer = tgui::TabContainer::create(); + tabContainer->setPosition(0, 0); + tabContainer->setSize({"100%", "100% - 36"}); + + auto saveButton = tgui::Button::create(); + bindTranslation(saveButton, "dialog.project_settings.save", &tgui::Button::setText); + saveButton->setPosition(2, "100% - 32"); + saveButton->setSize("100% - 4", 30); + saveButton->onClick([] { + Project *project = Editor::instance->getProject(); + + auto projectJson = project->toJson(); + auto basePath = project->getBasePath(); + + SaveFileText(TextFormat("%s/proj.rpgpp", basePath.c_str()), projectJson.dump().c_str()); + }); + + bindTranslation(this->currentWindow, "dialog.project_settings._label", &tgui::ChildWindow::setTitle); + + program = std::make_unique(tabContainer); + game = std::make_unique(tabContainer); + + tabContainer->getTabs()->select(0); + + this->currentWindow->add(tabContainer); + this->currentWindow->add(saveButton); + + this->currentWindow->setSize({"40%", "40%"}); +} + +void ProjectSettingsWindow::open() { + Project *project = Editor::instance->getProject(); + + program->setup(project); + game->setup(project); + + PopupWindow::open(); +} diff --git a/src/editor/childWindows/settingsPanel/general.cpp b/src/editor/childWindows/settingsPanel/general.cpp index 179cb820..8ab6eb16 100644 --- a/src/editor/childWindows/settingsPanel/general.cpp +++ b/src/editor/childWindows/settingsPanel/general.cpp @@ -1,17 +1,28 @@ + #include "childWindows/settingsPanel/general.hpp" + +#include +#include +#include + +#include "TGUI/String.hpp" #include "TGUI/Widgets/ComboBox.hpp" #include "TGUI/Widgets/GrowVerticalLayout.hpp" #include "TGUI/Widgets/HorizontalLayout.hpp" #include "TGUI/Widgets/Label.hpp" #include "TGUI/Widgets/ScrollablePanel.hpp" +#include "childWindows/settingsPanel/base.hpp" +#include "raylib.h" +#include "winapi.hpp" + +constexpr const int ANIMATION_DURATION = 200; SettingsPanelGeneral::SettingsPanelGeneral(tgui::TabContainer::Ptr tabContainer) - : SettingsPanelBase(tabContainer, "screen.options.general._label") { + : SettingsPanelBase(std::move(tabContainer), "screen.options.general._label") { TranslationService &ts = Editor::instance->getTranslations(); ThemeService &theme = Editor::instance->getThemeService(); - const tgui::ScrollablePanel::Ptr scrollPanel = - tgui::ScrollablePanel::create(); + const tgui::ScrollablePanel::Ptr scrollPanel = tgui::ScrollablePanel::create(); scrollPanel->setSize("100%", "100%"); scrollPanel->getRenderer()->setPadding(4); @@ -24,24 +35,22 @@ SettingsPanelGeneral::SettingsPanelGeneral(tgui::TabContainer::Ptr tabContainer) // Language const auto languageLayout = tgui::HorizontalLayout::create(); const auto languageSelector = tgui::ComboBox::create(); - for (auto [name, key] : ts.langKeyToName) { + for (const auto &[name, key] : ts.langKeyToName) { languageSelector->addItem(key, name); } - if (const auto langTranslation = ts.getKey("language"); - languageSelector->contains(langTranslation)) + if (const auto langTranslation = ts.getKey("language"); languageSelector->contains(langTranslation)) languageSelector->setSelectedItem(langTranslation); languageSelector->onItemSelect.connect([&](const tgui::String &item, const tgui::String &id) { - ConfigurationService &configService = - Editor::instance->getConfiguration(); + ConfigurationService &configService = Editor::instance->getConfiguration(); ts.setLanguage(ts.getLanguageIdentifierByKey(item.toStdString())); configService.setStringValue("language", id.toStdString()); configService.saveConfiguration(); // Can't think of a way to reload the menu bar without recreating it Editor::instance->getGui().initMenuBar(); - if (auto ptr = Editor::instance->getGui().menuBar.lock()) { + if (const auto ptr = Editor::instance->getGui().menuBar.lock()) { Editor::instance->getGui().currentScreen->bindMenuBarAndHK(ptr); } }); @@ -49,8 +58,7 @@ SettingsPanelGeneral::SettingsPanelGeneral(tgui::TabContainer::Ptr tabContainer) languageLayout->setSize({"100%", 30}); const auto languageLabel = tgui::Label::create(); languageLabel->setVerticalAlignment(tgui::VerticalAlignment::Center); - bindTranslation(languageLabel, "screen.options.general.language", - &tgui::Label::setText); + bindTranslation(languageLabel, "screen.options.general.language", &tgui::Label::setText); languageLayout->add(languageLabel); languageLayout->add(languageSelector); @@ -64,31 +72,57 @@ SettingsPanelGeneral::SettingsPanelGeneral(tgui::TabContainer::Ptr tabContainer) themeLabel->setVerticalAlignment(tgui::VerticalAlignment::Center); bindTranslation(themeLabel, "screen.options.general.theme", &tgui::Label::setText); - for (const auto &theme : theme.getThemes()) - themeSelector->addItem(theme); + for (const auto &themeName : theme.getThemes()) themeSelector->addItem(themeName); themeSelector->setSelectedItem(theme.current_theme_name); + this->promptUserBox = tgui::MessageBox::create(""); + bindTranslation(this->promptUserBox, "screen.options.general.theme", &tgui::MessageBox::setTitle); + bindTranslation(promptUserBox, "screen.options.general.theme_notice", &tgui::MessageBox::setText); + bindTranslationWithCallback(this->promptUserBox, [&](std::shared_ptr box, + TranslationService &ts) { + box->changeButtons(std::vector{ts.getKey("button.restart"), ts.getKey("button.restart_later")}); + }); + + this->promptUserBox->onButtonPress.connect([&](const tgui::String &text) { + if (text == ts.getKey("button.restart")) { + ChangeDirectory(GetApplicationDirectory()); +#ifdef __linux__ + + if (const FILE *handle = popen("./editor", "r"); handle == nullptr) { + fprintf(stderr, "failed to relaunch editor..\n"); + return; + } +#endif + +#ifdef _WIN32 + if (!WinCreateDetachedExecutable("editor.exe")) { + fprintf(stderr, "failed to relaunch editor..\n"); + return; + } +#endif + + exit(0); + } + Editor::instance->getGui().gui->remove(promptUserBox); + }); + themeSelector->onItemSelect.connect([&](const tgui::String &item) { - ConfigurationService &configService = - Editor::instance->getConfiguration(); + ConfigurationService &configService = Editor::instance->getConfiguration(); configService.setStringValue("theme", item.toStdString()); configService.saveConfiguration(); - theme.setTheme(item.toStdString()); - Editor::instance->getGui().reloadUi(); + + promptUserBox->setOrigin({0.5, 0.5}); + promptUserBox->setPosition({"50%", "50%"}); + + Editor::instance->getGui().gui->add(promptUserBox); }); themeLayout->add(themeLabel); themeLayout->add(themeSelector); - auto warnLabel = tgui::Label::create(); - bindTranslation(warnLabel, "screen.options.general.theme_notice", - &tgui::Label::setText); - warnLabel->setSize({"100%", 36}); - layout->add(languageLayout); layout->add(themeLayout); - layout->add(warnLabel); scrollPanel->add(layout); panel->add(scrollPanel); diff --git a/src/editor/childWindows/settingsPanel/hotkeys.cpp b/src/editor/childWindows/settingsPanel/hotkeys.cpp index 4f45384b..2e2e8eb7 100644 --- a/src/editor/childWindows/settingsPanel/hotkeys.cpp +++ b/src/editor/childWindows/settingsPanel/hotkeys.cpp @@ -1,4 +1,5 @@ #include "childWindows/settingsPanel/hotkeys.hpp" + #include "TGUI/Widgets/GrowVerticalLayout.hpp" #include "TGUI/Widgets/HorizontalLayout.hpp" #include "TGUI/Widgets/Label.hpp" @@ -11,8 +12,7 @@ SettingsPanelHotkeys::SettingsPanelHotkeys(tgui::TabContainer::Ptr tabContainer) HotkeyService &hks = Editor::instance->getHotkeyService(); TranslationService &ts = Editor::instance->getTranslations(); - const tgui::ScrollablePanel::Ptr scrollPanel = - tgui::ScrollablePanel::create(); + const tgui::ScrollablePanel::Ptr scrollPanel = tgui::ScrollablePanel::create(); scrollPanel->setSize("100%", "100%"); scrollPanel->getRenderer()->setPadding(4); @@ -36,8 +36,7 @@ SettingsPanelHotkeys::SettingsPanelHotkeys(tgui::TabContainer::Ptr tabContainer) ConfigurationService &cfgs = Editor::instance->getConfiguration(); hks.removeHotkey(id); hks.addHotkey(id, hk); - cfgs.setStringValue("hotkeys", id, - to_string(HotkeyService::pack(hk))); + cfgs.setStringValue("hotkeys", id, to_string(HotkeyService::pack(hk))); cfgs.saveConfiguration(); }); diff --git a/src/editor/childWindows/settingsWindow.cpp b/src/editor/childWindows/settingsWindow.cpp index a249e3cc..957e3dea 100644 --- a/src/editor/childWindows/settingsWindow.cpp +++ b/src/editor/childWindows/settingsWindow.cpp @@ -1,4 +1,5 @@ #include "childWindows/settingsWindow.hpp" + #include "TGUI/Widgets/TabContainer.hpp" #include "childWindows/popupWindow.hpp" #include "childWindows/settingsPanel/general.hpp" @@ -7,9 +8,7 @@ SettingsWindow::SettingsWindow() : PopupWindow("SettingsWindow") { this->currentWindow->setSize("540", "360"); this->currentWindow->setResizable(true); - bindTranslation(this->currentWindow, - "menu.options._label", - &tgui::ChildWindow::setTitle); + bindTranslation(this->currentWindow, "menu.options._label", &tgui::ChildWindow::setTitle); tgui::TabContainer::Ptr tabContainer = tgui::TabContainer::create(); tabContainer->setPosition(0, 0); @@ -18,4 +17,6 @@ SettingsWindow::SettingsWindow() : PopupWindow("SettingsWindow") { general = std::make_shared(tabContainer); hotkeys = std::make_shared(tabContainer); this->currentWindow->add(tabContainer); + + tabContainer->getTabs()->select(0); } diff --git a/src/editor/components/frameButton.cpp b/src/editor/components/frameButton.cpp index ae16f3c1..aacd7b35 100644 --- a/src/editor/components/frameButton.cpp +++ b/src/editor/components/frameButton.cpp @@ -1,4 +1,8 @@ #include "components/frameButton.hpp" + +#include +#include + #include "TGUI/Color.hpp" #include "TGUI/Cursor.hpp" #include "TGUI/Rect.hpp" @@ -7,24 +11,19 @@ #include "actor.hpp" #include "components/tooltip.hpp" #include "raylib.h" -#include -#include constexpr int CIRCLE_RADIUS = 10; constexpr float PADDING = 10.0f; -FrameButton::FrameButton(int frameIndex, Actor *actor) - : tgui::Button(), frameIndex(frameIndex), actor(actor) { - +FrameButton::FrameButton(const int frameIndex, Actor *actor) : frameIndex(frameIndex), actor(actor) { this->setMouseCursor(tgui::Cursor::Type::Hand); - this->setSize({50, "100%"}); + this->ButtonBase::setSize({50, "100%"}); this->updateSprite(); this->setToolTip(Tooltip::create(std::to_string(frameIndex))); - this->onPress.connect( - [this] { this->onFrameChange.emit(this, this->frameIndex); }); + this->onPress.connect([this] { this->onFrameChange.emit(this, this->frameIndex); }); } FrameButton::Ptr FrameButton::create(int frameIndex, Actor *actor) { @@ -33,22 +32,20 @@ FrameButton::Ptr FrameButton::create(int frameIndex, Actor *actor) { void FrameButton::updateSprite(bool reImport) { auto &tileset = actor->getTileSet(); - auto atlasPos = actor->getAnimationAtlasByIdx(this->frameIndex); + auto [x, y] = actor->getAnimationAtlasByIdx(this->frameIndex); const auto &texture = tileset.getTexture(); if (reImport || !this->sprite.isSet()) { // TGUI keeping the size of the previously imported sprite kinda messes // it up, so fix. - sprite.setSize({static_cast(texture.width), - static_cast(texture.height)}); + sprite.setSize({static_cast(texture.width), static_cast(texture.height)}); sprite.setTexture(tgui::Texture{tileset.getTextureSource()}); } - float width = static_cast(tileset.getTileWidth()), - height = static_cast(tileset.getTileHeight()); - float xPos = atlasPos.x * width, yPos = atlasPos.y * height; + auto width = static_cast(tileset.getTileWidth()), height = static_cast(tileset.getTileHeight()); + float xPos = x * width, yPos = y * height; sprite.setVisibleRect({ xPos, @@ -60,22 +57,18 @@ void FrameButton::updateSprite(bool reImport) { sprite.setPosition({-xPos - width / 2.0f, -yPos - height / 2.0f}); } -void FrameButton::draw(tgui::BackendRenderTarget &target, - tgui::RenderStates states) const { - - tgui::Button::draw(target, states); +void FrameButton::draw(tgui::BackendRenderTarget &target, tgui::RenderStates states) const { + Button::draw(target, states); float buttonWidth = m_size.x.getValue(), buttonHeight = m_size.y.getValue(); target.drawBorders(states, 2, {buttonWidth, buttonHeight}, - actor->getCurrentFrame() == this->frameIndex - ? tgui::Color::Blue - : tgui::Color::Black); + actor->getCurrentFrame() == this->frameIndex ? tgui::Color::Blue : tgui::Color::Black); - tgui::FloatRect visibleRect = this->sprite.getVisibleRect(); + const tgui::FloatRect visibleRect = this->sprite.getVisibleRect(); states.transform.translate({buttonWidth / 2.0f, buttonHeight / 2.0f}); - states.transform.scale({((buttonWidth - PADDING) / visibleRect.width), - ((buttonHeight - PADDING) / visibleRect.height)}); + states.transform.scale( + {((buttonWidth - PADDING) / visibleRect.width), ((buttonHeight - PADDING) / visibleRect.height)}); target.drawSprite(states, this->sprite); } diff --git a/src/editor/components/perfOverlay.cpp b/src/editor/components/perfOverlay.cpp index 46be7484..0b8688a1 100644 --- a/src/editor/components/perfOverlay.cpp +++ b/src/editor/components/perfOverlay.cpp @@ -1,9 +1,10 @@ #include "components/perfOverlay.hpp" -#include "raylib.h" + #include + +#include "raylib.h" PerformanceOverlay::PerformanceOverlay() { - for (int i = 0; i < SAMPLE_COUNT; i++) - samples[i] = 0; + for (int i = 0; i < SAMPLE_COUNT; i++) samples[i] = 0; index = 0; @@ -39,10 +40,8 @@ void PerformanceOverlay::UpdateScaling() { graphMax = graphMax * 0.9f + target * 0.1f; } -void PerformanceOverlay::DrawFPSLine(float ms, int x, int y, int w, int h, - Color color) { - if (ms > graphMax) - return; +void PerformanceOverlay::DrawFPSLine(float ms, int x, int y, int w, int h, Color color) { + if (ms > graphMax) return; float norm = ms / graphMax; float py = y + h - norm * h; @@ -61,8 +60,7 @@ void PerformanceOverlay::Update() { } void PerformanceOverlay::Draw(int x, int y, int w, int h) { - if (!enabled) - return; + if (!enabled) return; DrawRectangle(x, y, w, h, Fade(BLACK, 0.7f)); DrawRectangleLines(x, y, w, h, GRAY); @@ -74,8 +72,7 @@ void PerformanceOverlay::Draw(int x, int y, int w, int h) { float value = samples[idx]; float norm = value / graphMax; - if (norm > 1.0f) - norm = 1.0f; + if (norm > 1.0f) norm = 1.0f; float px = x + ((float)i / (SAMPLE_COUNT - 1)) * w; float py = y + h - norm * h; @@ -84,24 +81,21 @@ void PerformanceOverlay::Draw(int x, int y, int w, int h) { Color color = GREEN; - if (value > avgTime * spikeThreshold) - color = RED; + if (value > avgTime * spikeThreshold) color = RED; if (i > 0) { DrawLineV(prev, cur, color); - DrawTriangle({prev.x, y * 1.f + h}, {prev.x, prev.y}, - {cur.x, cur.y}, Fade(color, 0.15f)); + DrawTriangle({prev.x, y * 1.f + h}, {prev.x, prev.y}, {cur.x, cur.y}, Fade(color, 0.15f)); - DrawTriangle({prev.x, y * 1.f + h}, {cur.x, cur.y}, - {cur.x, y * 1.f + h}, Fade(color, 0.15f)); + DrawTriangle({prev.x, y * 1.f + h}, {cur.x, cur.y}, {cur.x, y * 1.f + h}, Fade(color, 0.15f)); } prev = cur; } - DrawFPSLine(16.67f, x, y, w, h, RED); // 60 FPS - DrawFPSLine(8.33f, x, y, w, h, ORANGE); // 120 FPS + DrawFPSLine(16.67f, x, y, w, h, RED); // 60 FPS + DrawFPSLine(8.33f, x, y, w, h, ORANGE); // 120 FPS DrawText(TextFormat("FPS: %d", GetFPS()), x, y - 18, 20, WHITE); diff --git a/src/editor/components/resizableCanvasBox.cpp b/src/editor/components/resizableCanvasBox.cpp index a86883eb..c3da9fbb 100644 --- a/src/editor/components/resizableCanvasBox.cpp +++ b/src/editor/components/resizableCanvasBox.cpp @@ -1,21 +1,17 @@ #include "components/resizableCanvasBox.hpp" -#include "raylib.h" + #include -bool bounded(float value, float min, float max) { - return value >= min && value <= max; -} +#include "raylib.h" -ResizableCanvasBox::ResizableCanvasBox(std::string id, float x, float y, - float width, float height, Color color, +bool bounded(float value, float min, float max) { return value >= min && value <= max; } + +ResizableCanvasBox::ResizableCanvasBox(std::string id, float x, float y, float width, float height, Color color, bool isResizable) - : id(id), x(x), y(y), width(width), height(height), color(color), - isResizable(isResizable) {} + : id(id), x(x), y(y), width(width), height(height), color(color), isResizable(isResizable) {} -ResizableCanvasBox::ResizableCanvasBox(std::string id, Rectangle rec, - Color color, bool isResizable) - : id(id), x(rec.x), y(rec.y), width(rec.width), height(rec.height), - color(color), isResizable(isResizable) {} +ResizableCanvasBox::ResizableCanvasBox(std::string id, Rectangle rec, Color color, bool isResizable) + : id(id), x(rec.x), y(rec.y), width(rec.width), height(rec.height), color(color), isResizable(isResizable) {} void ResizableCanvasBox::updateSize(float width, float height) { this->width = width; @@ -36,19 +32,18 @@ void ResizableCanvasBox::updateRec(Rectangle rec) { this->height = rec.height; } +Rectangle ResizableCanvasBox::getRectangle() { return {this->x, this->y, this->width, this->height}; } + bool ResizableCanvasBox::leftMousePressed(Vector2 mousePos) { resizeDirection = NONE; - if (mousePos.x >= x && mousePos.x <= x + width && mousePos.y >= y && - mousePos.y <= y + height) { - + if (mousePos.x >= x && mousePos.x <= x + width && mousePos.y >= y && mousePos.y <= y + height) { if (isResizable) { if (mousePos.x >= x && mousePos.x <= x + RESIZE_MARGIN) { resizeDirection |= LEFT; } - if (mousePos.x >= x + width - RESIZE_MARGIN && - mousePos.x <= x + width) { + if (mousePos.x >= x + width - RESIZE_MARGIN && mousePos.x <= x + width) { resizeDirection |= RIGHT; } @@ -56,8 +51,7 @@ bool ResizableCanvasBox::leftMousePressed(Vector2 mousePos) { resizeDirection |= TOP; } - if (mousePos.y >= y + height - RESIZE_MARGIN && - mousePos.y <= y + height) { + if (mousePos.y >= y + height - RESIZE_MARGIN && mousePos.y <= y + height) { resizeDirection |= BOTTOM; } } @@ -78,20 +72,15 @@ bool ResizableCanvasBox::leftMousePressed(Vector2 mousePos) { return false; } -void ResizableCanvasBox::mouseMoved(Vector2 mousePos, int snapWidth, - int snapHeight) { - if (!isResizing || !focused) - return; +void ResizableCanvasBox::mouseMoved(Vector2 mousePos, int snapWidth, int snapHeight) { + if (!isResizing || !focused) return; int dx = std::round((mousePos.x - startMousePos.x) / snapWidth) * snapWidth; - int dy = - std::round((mousePos.y - startMousePos.y) / snapHeight) * snapHeight; + int dy = std::round((mousePos.y - startMousePos.y) / snapHeight) * snapHeight; - if ((resizeDirection & LEFT) && prevWidth - dx < minSize) - dx = prevWidth - minSize; + if ((resizeDirection & LEFT) && prevWidth - dx < minSize) dx = prevWidth - minSize; - if ((resizeDirection & TOP) && prevHeight - dy < minSize) - dy = prevHeight - minSize; + if ((resizeDirection & TOP) && prevHeight - dy < minSize) dy = prevHeight - minSize; if (resizeDirection & LEFT) { x = prevX + dx; @@ -129,8 +118,7 @@ void ResizableCanvasBox::draw() { if (focused) { opacity = 0.5; } - DrawRectangleLinesEx(Rectangle{x, y, width, height}, 1, - Fade(BLACK, opacity)); + DrawRectangleLinesEx(Rectangle{x, y, width, height}, 1, Fade(BLACK, opacity)); DrawRectangleRec(Rectangle{x, y, width, height}, Fade(color, opacity)); // Implement draw logic here } diff --git a/src/editor/components/resizableContainer.cpp b/src/editor/components/resizableContainer.cpp index db3f33cd..28fa7208 100644 --- a/src/editor/components/resizableContainer.cpp +++ b/src/editor/components/resizableContainer.cpp @@ -1,94 +1,67 @@ #include "components/resizableContainer.hpp" + +#include + #include "TGUI/Backend/Renderer/BackendRenderTarget.hpp" #include "TGUI/Layout.hpp" #include "TGUI/Vector2.hpp" #include "TGUI/Widget.hpp" #include "TGUI/Widgets/Group.hpp" #include "raylib.h" -#include -bool bounded(int value, int min, int max) { - return value >= min && value <= max; -} +bool bounded(int value, int min, int max) { return value >= min && value <= max; } -ResizableContainer::ResizableContainer(const tgui::Layout2d &size, - const tgui::Layout2d &position) - : tgui::Group() { +ResizableContainer::ResizableContainer(const tgui::Layout2d &size, const tgui::Layout2d &position) : tgui::Group() { this->setSize(size); this->setPosition(position); } -void ResizableContainer::setMaxResizeWidth(int width) { - maxResizeWidth = width; -} +void ResizableContainer::setMaxResizeWidth(int width) { maxResizeWidth = width; } int ResizableContainer::getMaxResizeWidth() { return maxResizeWidth; } -void ResizableContainer::setMaxResizeHeight(int height) { - maxResizeHeight = height; -} +void ResizableContainer::setMaxResizeHeight(int height) { maxResizeHeight = height; } int ResizableContainer::getMaxResizeHeight() { return maxResizeHeight; } -void ResizableContainer::setMinResizeWidth(int width) { - minResizeWidth = width; -} -void ResizableContainer::setMinResizeHeight(int height) { - minResizeHeight = height; -} +void ResizableContainer::setMinResizeWidth(int width) { minResizeWidth = width; } +void ResizableContainer::setMinResizeHeight(int height) { minResizeHeight = height; } int ResizableContainer::getMinResizeWidth() { return minResizeWidth; } int ResizableContainer::getMinResizeHeight() { return minResizeHeight; } void ResizableContainer::setGrabberSize(int size) { grabberSize = size; } int ResizableContainer::getGrabberSize() { return grabberSize; } -void ResizableContainer::enableResize(ResizeDirection direction) { - resizeFlags |= static_cast(direction); -} +void ResizableContainer::enableResize(ResizeDirection direction) { resizeFlags |= static_cast(direction); } -void ResizableContainer::disableResize(ResizeDirection direction) { - resizeFlags &= ~static_cast(direction); -} +void ResizableContainer::disableResize(ResizeDirection direction) { resizeFlags &= ~static_cast(direction); } -bool ResizableContainer::isResizable(ResizeDirection direction) { - return resizeFlags & static_cast(direction); -} +bool ResizableContainer::isResizable(ResizeDirection direction) { return resizeFlags & static_cast(direction); } -ResizableContainer::Ptr -ResizableContainer::create(const tgui::Layout2d &size, - const tgui::Layout2d &position) { +ResizableContainer::Ptr ResizableContainer::create(const tgui::Layout2d &size, const tgui::Layout2d &position) { return std::make_shared(size, position); } -ResizableContainer::Ptr -ResizableContainer::copy(ResizableContainer::ConstPtr widget) { +ResizableContainer::Ptr ResizableContainer::copy(ResizableContainer::ConstPtr widget) { if (widget) { return std::static_pointer_cast(widget->clone()); } return nullptr; } -tgui::Widget::Ptr ResizableContainer::clone() const { - return std::make_shared(*this); -} +tgui::Widget::Ptr ResizableContainer::clone() const { return std::make_shared(*this); } -bool ResizableContainer::inEnabledGrabber(ResizeDirection direction, - tgui::Vector2f absolutePos) { - if (!isResizable(direction)) - return false; +bool ResizableContainer::inEnabledGrabber(ResizeDirection direction, tgui::Vector2f absolutePos) { + if (!isResizable(direction)) return false; switch (direction) { - case ResizeDirection::LEFT: - return bounded(absolutePos.x, 0, grabberSize) and - bounded(absolutePos.y, 0, getSize().y); - case ResizeDirection::RIGHT: - return bounded(absolutePos.x, getSize().x - grabberSize, - getSize().x) and - bounded(absolutePos.y, 0, getSize().y); - case ResizeDirection::TOP: - return bounded(absolutePos.y, 0, grabberSize) and - bounded(absolutePos.x, 0, getSize().x); - case ResizeDirection::BOTTOM: - return bounded(absolutePos.y, getSize().y - grabberSize, - getSize().y) and - bounded(absolutePos.x, 0, getSize().x); - default: - return false; + case ResizeDirection::LEFT: + return bounded(absolutePos.x, 0, grabberSize) and bounded(absolutePos.y, 0, getSize().y); + case ResizeDirection::RIGHT: + return bounded(absolutePos.x, getSize().x - grabberSize, getSize().x) and + bounded(absolutePos.y, 0, getSize().y); + case ResizeDirection::TOP: + return bounded(absolutePos.y, 0, grabberSize) and bounded(absolutePos.x, 0, getSize().x); + case ResizeDirection::BOTTOM: + return bounded(absolutePos.y, getSize().y - grabberSize, getSize().y) and + bounded(absolutePos.x, 0, getSize().x); + default: + return false; } } @@ -134,29 +107,24 @@ void ResizableContainer::manualMouseMoved(tgui::Vector2f pos) { tgui::Vector2f deltaMousePos = absolutePos - startMousePos; if (grabbingFlag == static_cast(ResizeDirection::LEFT)) { float newW = startSize.x.getValue() - deltaMousePos.x; - newW = std::clamp(newW, static_cast(minResizeWidth), - static_cast(maxResizeWidth)); + newW = std::clamp(newW, static_cast(minResizeWidth), static_cast(maxResizeWidth)); setSize(newW, startSize.y); setPosition(startPosition.x + deltaMousePos.x, startPosition.y); } else if (grabbingFlag == static_cast(ResizeDirection::RIGHT)) { float newW = startSize.x.getValue() + deltaMousePos.x; - newW = std::clamp(newW, static_cast(minResizeWidth), - static_cast(maxResizeWidth)); + newW = std::clamp(newW, static_cast(minResizeWidth), static_cast(maxResizeWidth)); setSize(newW, startSize.y); } else if (grabbingFlag == static_cast(ResizeDirection::TOP)) { float newH = startSize.y.getValue() - deltaMousePos.y; - newH = std::clamp(newH, static_cast(minResizeHeight), - static_cast(maxResizeHeight)); + newH = std::clamp(newH, static_cast(minResizeHeight), static_cast(maxResizeHeight)); setSize(startSize.x, newH); setPosition(startPosition.x, startPosition.y + deltaMousePos.y); } else if (grabbingFlag == static_cast(ResizeDirection::BOTTOM)) { float newH = startSize.y.getValue() + deltaMousePos.y; - newH = std::clamp(newH, static_cast(minResizeHeight), - static_cast(maxResizeHeight)); + newH = std::clamp(newH, static_cast(minResizeHeight), static_cast(maxResizeHeight)); setSize(startSize.x, newH); } - onResize.emit(this, tgui::Layout2d{getSize().x - startSize.x, - getSize().y - startSize.y}); + onResize.emit(this, tgui::Layout2d{getSize().x - startSize.x, getSize().y - startSize.y}); } void ResizableContainer::mouseMoved(tgui::Vector2f pos) { tgui::Group::mouseMoved(pos); @@ -165,9 +133,7 @@ void ResizableContainer::mouseMoved(tgui::Vector2f pos) { } } -void ResizableContainer::manualLeftMouseReleased(tgui::Vector2f pos) { - grabbingFlag = 0; -} +void ResizableContainer::manualLeftMouseReleased(tgui::Vector2f pos) { grabbingFlag = 0; } void ResizableContainer::leftMouseReleased(tgui::Vector2f pos) { tgui::Group::leftMouseReleased(pos); diff --git a/src/editor/components/tooltip.cpp b/src/editor/components/tooltip.cpp index 27b33b5d..89e05fd1 100644 --- a/src/editor/components/tooltip.cpp +++ b/src/editor/components/tooltip.cpp @@ -1,7 +1,9 @@ #include "components/tooltip.hpp" + +#include + #include "TGUI/Color.hpp" #include "TGUI/Widgets/Label.hpp" -#include Tooltip::Tooltip(const std::string &text) : tgui::Label() { this->setText(text); @@ -10,9 +12,7 @@ Tooltip::Tooltip(const std::string &text) : tgui::Label() { this->setTextSize(16); } -Tooltip::Ptr Tooltip::create(const std::string &text) { - return std::make_shared(text); -} +Tooltip::Ptr Tooltip::create(const std::string &text) { return std::make_shared(text); } Tooltip::Ptr Tooltip::copy(ConstPtr widget) { if (widget) { @@ -21,6 +21,4 @@ Tooltip::Ptr Tooltip::copy(ConstPtr widget) { return nullptr; } -tgui::Widget::Ptr Tooltip::clone() const { - return std::make_shared(*this); -} +tgui::Widget::Ptr Tooltip::clone() const { return std::make_shared(*this); } diff --git a/src/editor/editor.cpp b/src/editor/editor.cpp index f981c3e0..e69d9ac7 100644 --- a/src/editor/editor.cpp +++ b/src/editor/editor.cpp @@ -1,16 +1,17 @@ #include "editor.hpp" + +#include + #include "project.hpp" #include "raylib.h" #include "services/editorGuiService.hpp" #include "services/fileSystemService.hpp" #include "services/translationService.hpp" -#include Editor *Editor::instance; Editor::Editor() - : configurationService(), translationService(this), themeService(this), - hotkeyService(), project{nullptr} { + : configurationService(), translationService(this), themeService(this), hotkeyService(), project{nullptr} { instance = this; } @@ -33,17 +34,11 @@ HotkeyService &Editor::getHotkeyService() { return hotkeyService; } Project *Editor::getProject() const { return project.get(); } -RecentProjectService &Editor::getRecentProjectService() { - return recentProjectService; -} +RecentProjectService &Editor::getRecentProjectService() { return recentProjectService; } -ConfigurationService &Editor::getConfiguration() { - return configurationService; -} +ConfigurationService &Editor::getConfiguration() { return configurationService; } -void Editor::setProject(const std::string &path) { - project = std::make_unique(path); -} +void Editor::setProject(const std::string &path) { project = std::make_unique(path); } void Editor::unload() const { // Unload all the assets currently loaded and close the window. diff --git a/src/editor/fileInitVisitor.cpp b/src/editor/fileInitVisitor.cpp index b87b30e9..0a5ee5d6 100644 --- a/src/editor/fileInitVisitor.cpp +++ b/src/editor/fileInitVisitor.cpp @@ -9,6 +9,7 @@ #include "dialogue.hpp" #include "editor.hpp" #include "gamedata.hpp" +#include "interactable.hpp" #include "prop.hpp" #include "raylib.h" #include "room.hpp" @@ -24,6 +25,7 @@ FileInitVisitor::FileInitVisitor() { funcs[static_cast(EngineFileType::FILE_ACTOR)] = actor; funcs[static_cast(EngineFileType::FILE_PROP)] = prop; funcs[static_cast(EngineFileType::FILE_DIALOGUE)] = dialogue; + funcs[static_cast(EngineFileType::FILE_INTERACTABLE)] = interactable; } bool FileInitVisitor::funcIsEmpty(EngineFileType fileType) { return funcs[static_cast(fileType)] == nullptr; } @@ -166,3 +168,37 @@ void FileInitVisitor::dialogue(NewFileDialog::Ptr dialog) { } }); } + +void FileInitVisitor::interactable(NewFileDialog::Ptr dialog) { + dialog->hideFileField(); + + dialog->confirmButton->onPress([dialog] { + std::string title = dialog->titleField->getText().toStdString(); + + bool found = false; + for (auto &[key, val] : Editor::instance->getProject()->getInteractableNames()) { + std::string type = GetFileNameWithoutExt(key.c_str()); + + if (type == std::string(TextToLower(title.c_str()))) { + found = true; + break; + } + } + + if (!title.empty() && !found) { + std::unique_ptr interactable = + std::make_unique(title, Vector2{-1, -1}, _RPGPP_TILESIZE); + interactable->setDisplayTitle(title); + + std::string newFilePath = TextFormat("interactables/%s.rinter", TextToLower(title.c_str())); + nlohmann::json fileJson = interactable->dumpJson(); + SaveFileText(newFilePath.c_str(), fileJson.dump().c_str()); + + auto ptr = aurora::downcast(Editor::instance->getGui().currentScreen.get()); + ptr->addFileView(EngineFileType::FILE_INTERACTABLE, newFilePath); + ptr->addResourceButtons(EngineFileType::FILE_INTERACTABLE); + + dialog->window->close(); + } + }); +} diff --git a/src/editor/fileViews/actorFileView.cpp b/src/editor/fileViews/actorFileView.cpp index 2704a73d..7218d4ab 100644 --- a/src/editor/fileViews/actorFileView.cpp +++ b/src/editor/fileViews/actorFileView.cpp @@ -1,6 +1,5 @@ -// TODO: Timeline, where the user can add frames and remove them. - #include "fileViews/actorFileView.hpp" + #include "TGUI/String.hpp" #include "TGUI/Widgets/Label.hpp" #include "actor.hpp" @@ -21,8 +20,7 @@ ActorFileView::ActorFileView() { TranslationService &ts = Editor::instance->getTranslations(); this->actorView = ActorView::create(this); - Editor::instance->getGui().addUpdate( - WorldView::asUpdatable(this->actorView)); + Editor::instance->getGui().addUpdate(WorldView::asUpdatable(this->actorView)); auto canvasHeight = TextFormat("100%% - %d", BOTTOM_ANIMATION_PANEL); auto rightPanelOffset = TextFormat("100%% - %d", RIGHT_PANEL_W); @@ -36,16 +34,12 @@ ActorFileView::ActorFileView() { // The TileSet Editor this->tileSetField = FileField::create(); - bindTranslation(tileSetField->label, - "screen.project.roomview.tileset_file", - &tgui::Label::setText); - tileSetField->pathFilters = { - {tileSetField->label->getText(), {"*.rtiles"}}}; + bindTranslation(tileSetField->label, "screen.project.roomview.tileset_file", &tgui::Label::setText); + tileSetField->pathFilters = {{tileSetField->label->getText(), {"*.rtiles"}}}; tileSetField->callback = [this](const tgui::String &text) { actorView->actor->setTileSet(text.toStdString()); // fix for the atlas rectangle not sizing up properly. - actorView->setAtlasRect( - actorView->actor->getCurrentAnimationRectangle()); + actorView->setAtlasRect(actorView->actor->getCurrentAnimationRectangle()); frameEditor->updateFrameButtons(true); actorView->actor->resetAnimation(); }; @@ -53,11 +47,8 @@ ActorFileView::ActorFileView() { // Collision Rectangle Editor collisionField = RectangleField::create(); - bindTranslation(collisionField->label, - "screen.project.propview.collision", - &tgui::Label::setText); - collisionField->onChange( - [this](Rectangle r) { actorView->setCollisionRect(r); }); + bindTranslation(collisionField->label, "screen.project.propview.collision", &tgui::Label::setText); + collisionField->onChange([this](Rectangle r) { actorView->setCollisionRect(r); }); propBox->addRectangleField(collisionField); this->frameEditor = FrameEditor::create(this); @@ -78,14 +69,12 @@ void ActorFileView::init(tgui::Group::Ptr layout, VariantWrapper *variant) { this->actorView->setActor(ptrRaw); - this->tileSetField->setValue( - GetFileName(ptrRaw->getTileSetSource().c_str())); + this->tileSetField->setValue(GetFileName(ptrRaw->getTileSetSource().c_str())); this->collisionField->setValue(ptrRaw->getCollisionRect()); actorView->actor->onFrameChanged = [this](const int &frame) { this->frameEditor->onFrameChange(frame); - this->actorView->setAtlasRect( - actorView->actor->getCurrentAnimationRectangle()); + this->actorView->setAtlasRect(actorView->actor->getCurrentAnimationRectangle()); }; // NOTE: Always initialize this later. Otherwise, we might see diff --git a/src/editor/fileViews/codeFileView.cpp b/src/editor/fileViews/codeFileView.cpp deleted file mode 100644 index d5dadf7d..00000000 --- a/src/editor/fileViews/codeFileView.cpp +++ /dev/null @@ -1,70 +0,0 @@ -#include "fileViews/codeFileView.hpp" - -#include "editor.hpp" -#include "scriptFile.h" -#include "views/codeView.hpp" -#include "widgets/codeEditor.hpp" - -#include "tree_sitter/tree-sitter-lua.h" -#include -#include - -/* -void do_tree_node(TSTreeCursor cursor, TSNode node) { - printf("====== \n"); - printf("type: %s \n", ts_node_type(node)); - printf("start byte: %u \n", ts_node_start_byte(node)); - printf("end byte: %u \n", ts_node_end_byte(node)); - printf("====== \n"); - - auto copy = ts_tree_cursor_copy(&cursor); - bool hasChild = ts_tree_cursor_goto_first_child(©); - if (hasChild) { - do_tree_node(copy, ts_tree_cursor_current_node(©)); - } - - auto copy2 = ts_tree_cursor_copy(&cursor); - bool hasSibling = ts_tree_cursor_goto_next_sibling(©2); - if (hasSibling) { - do_tree_node(copy2, ts_tree_cursor_current_node(©2)); - } -} -*/ - -CodeFileView::CodeFileView() { - codeEditor = CodeView::create(); - - Editor::instance->getGui().addUpdate( - codeEditor->asUpdatable(this->codeEditor)); - - codeEditor->setTextSize(24); - codeEditor->setSize({"100%", "100%"}); - - widgetContainer.push_back(codeEditor); -} - -void CodeFileView::init(tgui::Group::Ptr layout, VariantWrapper *variant) { - this->variant = variant; - - if (variant != nullptr) { - const auto ptr = dynamic_cast *>(variant); - - /* - TSParser *parser = ts_parser_new(); - - ts_parser_set_language(parser, tree_sitter_lua()); - - auto tree = ts_parser_parse_string( - parser, nullptr, ptr->get()->getFileContents().c_str(), - ptr->get()->getFileContents().size()); - - auto root = ts_tree_root_node(tree); - - auto cursor = ts_tree_cursor_new(root); - do_tree_node(cursor, root); - */ - - codeEditor->setCode(ptr->get()); - addWidgets(layout); - } -} diff --git a/src/editor/fileViews/dialogueFileView.cpp b/src/editor/fileViews/dialogueFileView.cpp index 6807f689..d8a635d9 100644 --- a/src/editor/fileViews/dialogueFileView.cpp +++ b/src/editor/fileViews/dialogueFileView.cpp @@ -1,41 +1,54 @@ #include "fileViews/dialogueFileView.hpp" + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "TGUI/Cursor.hpp" #include "TGUI/Layout.hpp" #include "TGUI/String.hpp" #include "TGUI/Texture.hpp" #include "TGUI/Widgets/Button.hpp" +#include "TGUI/Widgets/ComboBox.hpp" #include "TGUI/Widgets/EditBox.hpp" #include "TGUI/Widgets/FileDialog.hpp" +#include "TGUI/Widgets/Group.hpp" #include "TGUI/Widgets/GrowVerticalLayout.hpp" #include "TGUI/Widgets/Panel.hpp" #include "TGUI/Widgets/TextArea.hpp" #include "bindTranslation.hpp" +#include "childWindows/addDelayDialogueWindow.hpp" +#include "childWindows/addDialogueOptionWindow.hpp" +#include "childWindows/colorSelectWindow.hpp" +#include "childWindows/editDialogueOptionWindow.hpp" #include "dialogue.hpp" #include "editor.hpp" #include "raylib.h" #include "services/fileSystemService.hpp" #include "services/translationService.hpp" #include "variant.hpp" -#include -#include -#include -#include -#include +#include "widgets/dialogueEditor.hpp" +#include "widgets/propertyFields/interPropField.hpp" DialogueFileView::DialogueFileView() { + dialogue = nullptr; + TranslationService &ts = Editor::instance->getTranslations(); - noImageTexture = tgui::Texture( - Editor::instance->getFs().getResourcePath("no-image.png")); + noImageTexture = tgui::Texture(Editor::instance->getFs().getResourcePath("no-image.png")); - deleteTexture = - tgui::Texture(Editor::instance->getFs().getResourcePath("delete.png")); + deleteTexture = tgui::Texture(Editor::instance->getFs().getResourcePath("delete.png")); auto toolsPanel = tgui::Panel::create({"100%", 32}); toolsPanel->getRenderer()->setPadding({4, 4}); newLineButton = tgui::Button::create(); - bindTranslation(newLineButton, - "screen.project.dialogueview.add_new_line", - &tgui::Button::setText); + bindTranslation(newLineButton, "screen.project.dialogueview.add_new_line", &tgui::Button::setText); newLineButton->setSize("20%", "100%"); toolsPanel->add(newLineButton); @@ -45,10 +58,8 @@ DialogueFileView::DialogueFileView() { mainPanel->setPosition(0, 32); mainPanel->getRenderer()->setPadding({16, 16}); - mainPanel->getVerticalScrollbar()->setPolicy( - tgui::Scrollbar::Policy::Automatic); - mainPanel->getHorizontalScrollbar()->setPolicy( - tgui::Scrollbar::Policy::Never); + mainPanel->getVerticalScrollbar()->setPolicy(tgui::Scrollbar::Policy::Automatic); + mainPanel->getHorizontalScrollbar()->setPolicy(tgui::Scrollbar::Policy::Never); vertLayout = tgui::GrowVerticalLayout::create(); vertLayout->getRenderer()->setSpaceBetweenWidgets(20.0f); @@ -56,20 +67,25 @@ DialogueFileView::DialogueFileView() { widgetContainer.push_back(mainPanel); } -tgui::Panel::Ptr DialogueFileView::makeLinePanel(DialogueBin &data, - DialogueLine line, size_t i) { +constexpr int MAXIMUM_TEXT_SIZE = 32; +constexpr int MINIMUM_TEXT_SIZE = 16; + +tgui::Panel::Ptr DialogueFileView::makeLinePanel(DialogueBin &data, DialogueLine line, size_t i) { TranslationService &ts = Editor::instance->getTranslations(); auto panel = tgui::Panel::create({"100%", DIALOGUE_PANEL_HEIGHT}); panel->getRenderer()->setPadding({16, 16}); + /// left group + auto leftGroup = tgui::Group::create({"10%", "100%"}); + panel->add(leftGroup); + tgui::Layout2d portraitLayout = {"100% - 40", "100% - 40"}; auto portraitPic = tgui::Picture::create(); portraitPic->setPosition(0, 40); portraitPic->setSize("height", "100% - 40"); if (line.hasPortrait) { - auto filePath = Editor::instance->getProject()->getResourcePath( - EngineFileType::FILE_IMAGE, line.imageId); + auto filePath = Editor::instance->getProject()->getResourcePath(EngineFileType::FILE_IMAGE, line.imageId); if (FileExists(filePath.c_str())) { tgui::Texture texture(filePath); portraitPic->getRenderer()->setTexture(texture); @@ -83,48 +99,163 @@ tgui::Panel::Ptr DialogueFileView::makeLinePanel(DialogueBin &data, if (data.lines.at(i).hasPortrait) { auto fileDialog = tgui::FileDialog::create(); fileDialog->setFileTypeFilters({{"Images", {"*.png", "*.jpg"}}}); - fileDialog->onFileSelect( - [&data, i, portraitWeak](const tgui::String &path) { - data.lines.at(i).imageId = - GetFileName(path.toStdString().c_str()); - tgui::Texture texture(path); - portraitWeak.lock()->getRenderer()->setTexture(texture); - }); + fileDialog->onFileSelect([&data, i, portraitWeak](const tgui::String &path) { + data.lines.at(i).imageId = GetFileName(path.toStdString().c_str()); + tgui::Texture texture(path); + portraitWeak.lock()->getRenderer()->setTexture(texture); + }); Editor::instance->getGui().gui->add(fileDialog); } }); - panel->add(portraitPic); + leftGroup->add(portraitPic); + + /// center group + auto centerGroup = tgui::Group::create({"80%", "100%"}); + centerGroup->setPosition({"10%", 0}); + panel->add(centerGroup); auto charNameEdit = tgui::EditBox::create(); - charNameEdit->setSize({"100% - 210 - 40", 32}); - charNameEdit->setPosition(210, 0); + charNameEdit->setPosition({0, 0}); + charNameEdit->setSize({"10%", 36}); charNameEdit->setText(line.characterName); - charNameEdit->onTextChange([&line, &data, i](const tgui::String &text) { - line.characterName = text.toStdString(); - data.lines.at(i).characterName = text.toStdString(); + charNameEdit->onTextChange( + [&data, i](const tgui::String &text) { data.lines.at(i).characterName = text.toStdString(); }); + centerGroup->add(charNameEdit); + + auto diagTextEdit = DialogueEditor::create(); + diagTextEdit->setMouseCursor(tgui::Cursor::Type::Text); + diagTextEdit->setPosition({0, 40}); + diagTextEdit->setSize("50%", "100% - 40"); + diagTextEdit->setText(line.text); + diagTextEdit->onTextChange([&data, i](const tgui::String &text) { data.lines.at(i).text = text.toStdString(); }); + dialogueBoxes.push_back(diagTextEdit); + + centerGroup->add(diagTextEdit); + + auto selectColorButton = tgui::Button::create(); + selectColorButton->setPosition({"10% + 4", 0}); + selectColorButton->setSize("10%", 36); + bindTranslation(selectColorButton, "screen.project.dialogueview.select_a_color", + &tgui::Button::setText); + std::weak_ptr weakEditor = diagTextEdit; + selectColorButton->onPress.connect([weakEditor] { + if (auto capture = weakEditor.lock()) { + auto selectColorWindow = reinterpret_cast( + Editor::instance->getGui().getChildWindowSubService()->getWindow("select_a_color")); + + selectColorWindow->open(capture); + } }); - panel->add(charNameEdit); + centerGroup->add(selectColorButton); + + auto addDelayButton = tgui::Button::create(); + addDelayButton->setPosition({"20% + 8", 0}); + addDelayButton->setSize("10%", 36); + bindTranslation(addDelayButton, "screen.project.dialogueview.add_a_delay", &tgui::Button::setText); + addDelayButton->onPress.connect([weakEditor] { + if (auto capture = weakEditor.lock()) { + auto delayWindow = reinterpret_cast( + Editor::instance->getGui().getChildWindowSubService()->getWindow("add_a_delay")); + + delayWindow->open(capture); + } + }); + centerGroup->add(addDelayButton); - auto diagTextEdit = tgui::TextArea::create(); - diagTextEdit->setPosition(210, 32 + 8); - diagTextEdit->setSize({"100% - 210 - 40", "100% - 40"}); - diagTextEdit->setText(line.text); - diagTextEdit->onTextChange([&data, i](const tgui::String &text) { - data.lines.at(i).text = text.toStdString(); + auto selectFontComboBox = tgui::ComboBox::create(); + selectFontComboBox->setPosition({"30% + 12", 0}); + selectFontComboBox->setSize("10%", 36); + bindTranslation(selectFontComboBox, "screen.project.dialogueview.select_a_font", + &tgui::ComboBox::setDefaultText); + + Project *project = Editor::instance->getProject(); + auto fontPaths = project->getPaths(EngineFileType::FILE_FONT); + + std::for_each(fontPaths.begin(), fontPaths.end(), [&selectFontComboBox](const std::string &fontPath) { + auto filename = GetFileNameWithoutExt(fontPath.c_str()); + selectFontComboBox->addItem(filename); }); - panel->add(diagTextEdit); + + std::weak_ptr weakFontBox = selectFontComboBox; + selectFontComboBox->onItemSelect.connect([weakEditor, weakFontBox](const tgui::String &selectedIndex) { + if (weakEditor.expired() || weakFontBox.expired()) { + return; + } + + auto editor = weakEditor.lock(); + auto box = weakFontBox.lock(); + + editor->addXmlTagWithProperties("font", {{"font", selectedIndex.toStdString()}}); + box->deselectItem(); + }); + centerGroup->add(selectFontComboBox); + + auto textSizeComboBox = tgui::ComboBox::create(); + textSizeComboBox->setPosition({"40% + 16", 0}); + textSizeComboBox->setSize("10%", 36); + + // For convenience, this code calculates the wanted text sizes automatically. + int textAddition = MAXIMUM_TEXT_SIZE / (MAXIMUM_TEXT_SIZE - MINIMUM_TEXT_SIZE); + for (int i = MINIMUM_TEXT_SIZE; i <= MAXIMUM_TEXT_SIZE; i += textAddition) { + textSizeComboBox->addItem(std::to_string(i)); + } + + bindTranslation(textSizeComboBox, "screen.project.dialogueview.select_a_text_size", + &tgui::ComboBox::setDefaultText); + + std::weak_ptr weakTextSizeBox = textSizeComboBox; + textSizeComboBox->onItemSelect.connect([weakEditor, weakTextSizeBox](const tgui::String &selectedIndex) { + if (weakEditor.expired() || weakTextSizeBox.expired()) { + return; + } + + auto editor = weakEditor.lock(); + auto box = weakTextSizeBox.lock(); + + editor->addXmlTagWithProperties("textSize", {{"size", selectedIndex.toStdString()}}); + box->deselectItem(); + }); + centerGroup->add(textSizeComboBox); + + auto addOptionButton = tgui::Button::create(); + bindTranslation(addOptionButton, "screen.project.dialogueview.add_option", &tgui::Button::setText); + addOptionButton->setPosition("80% + 20", 0); + addOptionButton->setSize(220, 36); + addOptionButton->onClick([this, i] { + auto *popupPtr = Editor::instance->getGui().getChildWindowSubService()->getWindow("add_dialogue_option"); + auto *addDialogueOptionWindow = static_cast(popupPtr); + + addDialogueOptionWindow->dialogue = this->dialogue; + addDialogueOptionWindow->lineIndex = i; + addDialogueOptionWindow->fileView = this; + + addDialogueOptionWindow->open(); + }); + centerGroup->add(addOptionButton); + + auto optionsPanel = tgui::ScrollablePanel::create(); + optionsPanel->setPosition({"50% + 4", 32 + 8}); + optionsPanel->setSize("50% - 4", "100% - 40"); + + auto optionsLayout = tgui::GrowVerticalLayout::create(); + optionsPanel->add(optionsLayout); + + optionPanels.push_back(optionsLayout); + + initOptionPanel(i); + + centerGroup->add(optionsPanel); auto hasImageCheck = tgui::CheckBox::create(); - bindTranslation( - hasImageCheck, "screen.project.dialogueview.has_a_portrait", - &tgui::CheckBox::setText); + bindTranslation(hasImageCheck, "screen.project.dialogueview.has_a_portrait", + &tgui::CheckBox::setText); + hasImageCheck->setPosition({0, 0}); hasImageCheck->setSize(32, 32); hasImageCheck->setChecked(line.hasPortrait); std::weak_ptr weakDiagText = diagTextEdit; - hasImageCheck->onCheck([this, &data, i, portraitPic, - weakDiagText](bool value) { + hasImageCheck->onCheck([this, &data, i, portraitPic, weakDiagText](bool value) { data.lines.at(i).hasPortrait = value; if (!value) { data.lines.at(i).imageId = ""; @@ -141,16 +272,14 @@ tgui::Panel::Ptr DialogueFileView::makeLinePanel(DialogueBin &data, } } }); - panel->add(hasImageCheck); + leftGroup->add(hasImageCheck); auto deleteButton = tgui::BitmapButton::create(); deleteButton->setSize({32, 32}); deleteButton->setPosition("100% - 32", 0); deleteButton->setImage(deleteTexture); deleteButton->onClick([this, &data, i] { - mainPanel->setContentSize( - {0, static_cast((DIALOGUE_PANEL_HEIGHT + 8) * - (data.lines.size()))}); + mainPanel->setContentSize({0, static_cast((DIALOGUE_PANEL_HEIGHT + 8) * (data.lines.size()))}); data.lines.erase(data.lines.begin() + i); vertLayout->remove(linePanels.at(i)); @@ -161,6 +290,40 @@ tgui::Panel::Ptr DialogueFileView::makeLinePanel(DialogueBin &data, return panel; } +void DialogueFileView::initOptionPanel(int lineIndex) { + auto &line = dialogue->getData().lines[lineIndex]; + auto &panel = optionPanels.at(lineIndex); + panel->removeAllWidgets(); + + if (line.hasOptions) { + int i = 0; + for (auto &option : line.options) { + auto optionItem = InterPropField::create(); + optionItem->setSize({"100%", 32}); + optionItem->label->setText(option.title); + optionItem->value->setText(option.nextDialogue); + + optionItem->value->onClick([this, lineIndex, i] { + auto *popupPtr = + Editor::instance->getGui().getChildWindowSubService()->getWindow("edit_dialogue_option"); + auto *editDialogueOptionWindow = static_cast(popupPtr); + + editDialogueOptionWindow->setup(dialogue, lineIndex, i); + editDialogueOptionWindow->fileView = this; + editDialogueOptionWindow->open(); + }); + + optionItem->remove->onClick([this, i, lineIndex, &line] { + line.options.erase(line.options.begin() + i); + initOptionPanel(lineIndex); + }); + + panel->add(optionItem); + i++; + } + } +} + void DialogueFileView::init(tgui::Group::Ptr layout, VariantWrapper *variant) { this->variant = variant; @@ -168,6 +331,8 @@ void DialogueFileView::init(tgui::Group::Ptr layout, VariantWrapper *variant) { const auto ptr = dynamic_cast *>(variant); const auto dialogue = ptr->get(); + this->dialogue = dialogue; + auto &data = dialogue->getData(); newLineButton->onClick([this, &dialogue, &data] { @@ -184,14 +349,10 @@ void DialogueFileView::init(tgui::Group::Ptr layout, VariantWrapper *variant) { vertLayout->add(panel); linePanels.push_back(panel); - mainPanel->setContentSize( - {0, static_cast((DIALOGUE_PANEL_HEIGHT + 8) * - (data.lines.size() + 1))}); + mainPanel->setContentSize({0, static_cast((DIALOGUE_PANEL_HEIGHT + 8) * (data.lines.size() + 1))}); }); - mainPanel->setContentSize( - {0, static_cast((DIALOGUE_PANEL_HEIGHT + 8) * - (data.lines.size() + 1))}); + mainPanel->setContentSize({0, static_cast((DIALOGUE_PANEL_HEIGHT + 8) * (data.lines.size() + 1))}); int i = 0; for (auto line : dialogue->getData().lines) { diff --git a/src/editor/fileViews/emptyView.cpp b/src/editor/fileViews/emptyView.cpp index 6017abfe..a29acad8 100644 --- a/src/editor/fileViews/emptyView.cpp +++ b/src/editor/fileViews/emptyView.cpp @@ -1,4 +1,5 @@ #include "fileViews/emptyView.hpp" + #include "TGUI/Widgets/Group.hpp" #include "TGUI/Widgets/Label.hpp" #include "bindTranslation.hpp" @@ -9,14 +10,11 @@ EmptyFileView::EmptyFileView() { TranslationService &ts = Editor::instance->getTranslations(); auto noticeText = tgui::Label::create(); - bindTranslation(noticeText, "screen.project.emptyview.notice", - &tgui::Label::setText); + bindTranslation(noticeText, "screen.project.emptyview.notice", &tgui::Label::setText); noticeText->setPosition("50%", "50%"); noticeText->setOrigin(0.5, 0.5); noticeText->setTextSize(24); widgetContainer.push_back(noticeText); } -void EmptyFileView::init(tgui::Group::Ptr layout, VariantWrapper *variant) { - addWidgets(layout); -} +void EmptyFileView::init(tgui::Group::Ptr layout, VariantWrapper *variant) { addWidgets(layout); } diff --git a/src/editor/fileViews/fileView.cpp b/src/editor/fileViews/fileView.cpp index 3c99853f..1890d5e3 100644 --- a/src/editor/fileViews/fileView.cpp +++ b/src/editor/fileViews/fileView.cpp @@ -1,9 +1,11 @@ #include "fileViews/fileView.hpp" -#include "actions/action.hpp" + #include #include #include +#include "actions/action.hpp" + FileView::FileView() {} FileView::~FileView() {} diff --git a/src/editor/fileViews/fontFileView.cpp b/src/editor/fileViews/fontFileView.cpp index 24cc04ec..776f5918 100644 --- a/src/editor/fileViews/fontFileView.cpp +++ b/src/editor/fileViews/fontFileView.cpp @@ -1,4 +1,7 @@ #include "fileViews/fontFileView.hpp" + +#include + #include "TGUI/String.hpp" #include "TGUI/Widgets/EditBox.hpp" #include "TGUI/Widgets/Panel.hpp" @@ -8,7 +11,6 @@ #include "variant.hpp" #include "views/fontView.hpp" #include "views/worldView.hpp" -#include FontFileView::FontFileView() { fontView = FontView::create(); @@ -26,18 +28,14 @@ FontFileView::FontFileView() { fontSizeField->setMinimum(8.0f); fontSizeField->setMaximum(160.0); fontSizeField->setValue(16.0f); - fontSizeField->onValueChange([this](float value) { - fontView->setBaseFontSize(static_cast(floor(value))); - }); + fontSizeField->onValueChange([this](float value) { fontView->setBaseFontSize(static_cast(floor(value))); }); topPanel->add(fontSizeField); auto fontTextField = tgui::EditBox::create(); fontTextField->setSize("100% - 140", "100%"); fontTextField->setPosition(124.0f, 0); fontTextField->setText(fontView->getText()); - fontTextField->onTextChange([this](const tgui::String &text) { - fontView->setText(text.toStdString()); - }); + fontTextField->onTextChange([this](const tgui::String &text) { fontView->setText(text.toStdString()); }); topPanel->add(fontTextField); widgetContainer.push_back(fontView); diff --git a/src/editor/fileViews/imageFileView.cpp b/src/editor/fileViews/imageFileView.cpp index 2f8e9574..dd95b9cf 100644 --- a/src/editor/fileViews/imageFileView.cpp +++ b/src/editor/fileViews/imageFileView.cpp @@ -1,11 +1,13 @@ #include "fileViews/imageFileView.hpp" + +#include + #include "TGUI/Widgets/Label.hpp" #include "editor.hpp" #include "raylib.h" #include "saveables/imageWrapper.hpp" #include "views/imageView.hpp" #include "views/worldView.hpp" -#include ImageFileView::ImageFileView() { imageView = ImageView::create(); @@ -36,9 +38,8 @@ void ImageFileView::init(tgui::Group::Ptr layout, VariantWrapper *variant) { auto image = ptr->get(); imageView->setImage(image); - infoLabel->setText(TextFormat("%s | Image Size: %ix%i", - GetFileName(image->source.c_str()), - image->image.width, image->image.height)); + infoLabel->setText(TextFormat("%s | Image Size: %ix%i", GetFileName(image->source.c_str()), image->image.width, + image->image.height)); addWidgets(layout); } \ No newline at end of file diff --git a/src/editor/fileViews/interactableFileView.cpp b/src/editor/fileViews/interactableFileView.cpp new file mode 100644 index 00000000..8208f054 --- /dev/null +++ b/src/editor/fileViews/interactableFileView.cpp @@ -0,0 +1,82 @@ +#include "fileViews/interactableFileView.hpp" + +#include "TGUI/String.hpp" +#include "TGUI/Widgets/Label.hpp" +#include "bindTranslation.hpp" +#include "childWindows/newPropWindow.hpp" +#include "editor.hpp" +#include "interactable.hpp" +#include "raylib.h" +#include "widgets/propertiesBox.hpp" +#include "widgets/propertyFields/boolField.hpp" +#include "widgets/propertyFields/intField.hpp" +#include "widgets/propertyFields/textField.hpp" + +InteractableFileView::InteractableFileView() { + auto props = PropertiesBox::create(); + props->setSize({RIGHT_PANEL_W, "100%"}); + props->setPosition({TextFormat("100%% - %d", RIGHT_PANEL_W), 0}); + + nameField = TextField::create(); + bindTranslation(nameField->label, "screen.project.interactableview.display_name", + &tgui::Label::setText); + nameField->value->onTextChange([this](const tgui::String &text) { + if (variant != nullptr) { + const auto ptr = dynamic_cast *>(variant); + const auto interactable = ptr->get(); + + interactable->setDisplayTitle(text.toStdString()); + } + }); + props->addTextField(nameField); + + scriptField = FileField::create(); + scriptField->pathFilters = {{"Script", {"*.lua"}}}; + bindTranslation(scriptField->label, "screen.project.interactableview.script", &tgui::Label::setText); + scriptField->callback = [this](const tgui::String &path) { + if (variant != nullptr) { + const auto ptr = dynamic_cast *>(variant); + const auto interactable = ptr->get(); + + interactable->setScriptSourcePath(TextFormat("scripts/%s", GetFileName(path.toStdString().c_str()))); + } + }; + props->addFileField(scriptField); + + onTouchField = BoolField::create(); + bindTranslation(onTouchField->label, "screen.project.interactableview.on_touch", + &tgui::Label::setText); + onTouchField->value->onChange([this](bool value) { + if (variant != nullptr) { + const auto ptr = dynamic_cast *>(variant); + const auto interactable = ptr->get(); + + interactable->setOnTouch(value); + } + }); + props->addBooleanField(onTouchField); + + interProps = PropertiesBox::create(); + + props->addPropertiesBox(interProps); + + widgetContainer.push_back(props); +} + +void InteractableFileView::init(tgui::Group::Ptr layout, VariantWrapper *variant) { + this->variant = variant; + + if (variant != nullptr) { + const auto ptr = dynamic_cast *>(variant); + const auto interactable = ptr->get(); + + nameField->value->setText(interactable->getDisplayTitle()); + scriptField->value->setText(GetFileName(interactable->getScriptSourcePath().c_str())); + onTouchField->value->setChecked(interactable->isOnTouch()); + + interProps->interactable = interactable; + interProps->addPropsJson(interactable->getProps(), true, true); + + addWidgets(layout); + } +} diff --git a/src/editor/fileViews/propFileView.cpp b/src/editor/fileViews/propFileView.cpp index 338ca1de..54c0455c 100644 --- a/src/editor/fileViews/propFileView.cpp +++ b/src/editor/fileViews/propFileView.cpp @@ -1,4 +1,5 @@ #include "fileViews/propFileView.hpp" + #include "TGUI/String.hpp" #include "bindTranslation.hpp" #include "editor.hpp" @@ -6,7 +7,9 @@ #include "prop.hpp" #include "raylib.h" #include "variant.hpp" +#include "views/propPreview.hpp" #include "views/propView.hpp" +#include "views/worldView.hpp" #include "widgets/propertiesBox.hpp" #include "widgets/propertyFields/boolField.hpp" #include "widgets/propertyFields/fileField.hpp" @@ -23,9 +26,7 @@ PropFileView::PropFileView() { propBox->setPosition({TextFormat("100%% - %d", RIGHT_PANEL_W), 0}); hasInteractableField = BoolField::create(); - bindTranslation(hasInteractableField->label, - "screen.project.propview.has_interactable", - &tgui::Label::setText); + bindTranslation(hasInteractableField->label, "screen.project.propview.has_interactable", &tgui::Label::setText); hasInteractableField->value->onChange([this](bool value) { propView->getProp()->setHasInteractable(value); interactableTypeField->setEnabled(value); @@ -38,47 +39,39 @@ PropFileView::PropFileView() { propBox->addBooleanField(hasInteractableField); interactableTypeField = SelectField::create(); - bindTranslation(interactableTypeField->label, - "screen.project.propview.interactable_type", - &tgui::Label::setText); - for (const auto &[k, v] : - Editor::instance->getProject()->getInteractableNames()) { + bindTranslation(interactableTypeField->label, "screen.project.propview.interactable_type", &tgui::Label::setText); + for (const auto &[k, v] : Editor::instance->getProject()->getInteractableNames()) { interactableTypeField->value->addItem(GetFileNameWithoutExt(k.c_str())); } interactableTypeField->value->onItemSelect( - [this](const tgui::String &item) { - propView->getProp()->setInteractableType(item.toStdString()); - }); + [this](const tgui::String &item) { propView->getProp()->setInteractableType(item.toStdString()); }); propBox->addSelectField(interactableTypeField); propImageField = FileField::create(); - bindTranslation(propImageField->label, "screen.project.propview.image", - &tgui::Label::setText); - propImageField->pathFilters = { - {"Image", {"*.png"}}}; // TODO: Add more image types + bindTranslation(propImageField->label, "screen.project.propview.image", &tgui::Label::setText); + propImageField->pathFilters = {{"Image", {"*.png"}}}; // TODO: Add more image types propImageField->callback = [this](const tgui::String &path) { propView->getProp()->setTextureFromPath(path.toStdString()); }; propBox->addFileField(propImageField); atlasRectField = RectangleField::create(); - bindTranslation(atlasRectField->label, "screen.project.propview.atlas", - &tgui::Label::setText); - atlasRectField->onChange( - [this](Rectangle r) { propView->updateAtlasRect(r); }); + bindTranslation(atlasRectField->label, "screen.project.propview.atlas", &tgui::Label::setText); + atlasRectField->onChange([this](Rectangle r) { propView->updateAtlasRect(r); }); propBox->addRectangleField(atlasRectField); collisionsField = RectangleField::create(); - bindTranslation(collisionsField->label, "screen.project.propview.collision", - &tgui::Label::setText); - collisionsField->onChange( - [this](Rectangle r) { propView->updateCollisionRect(r); }); + bindTranslation(collisionsField->label, "screen.project.propview.collision", &tgui::Label::setText); + collisionsField->onChange([this](Rectangle r) { propView->updateCollisionRect(r); }); propBox->addRectangleField(collisionsField); - propView->onUpdatedAtlasRect( - [this](Rectangle r) { atlasRectField->setValue(r); }); - propView->onUpdatedCollisionRect( - [this](Rectangle r) { collisionsField->setValue(r); }); + propPreview = PropPreview::create(); + Editor::instance->getGui().addUpdate(WorldView::asUpdatable(propPreview)); + propPreview->setSize({"100%", 200}); + propBox->addWidget(propPreview); + + propView->onUpdatedAtlasRect([this](Rectangle r) { atlasRectField->setValue(r); }); + propView->onUpdatedCollisionRect([this](Rectangle r) { collisionsField->setValue(r); }); widgetContainer.push_back(propBox); widgetContainer.push_back(propView); } @@ -91,8 +84,7 @@ void PropFileView::init(tgui::Group::Ptr layout, VariantWrapper *variant) { auto ptr = dynamic_cast *>(variant); auto prop = ptr->get(); - if (prop == nullptr) - return; + if (prop == nullptr) return; propView->setProp(prop); hasInteractableField->value->setChecked(prop->getHasInteractable()); @@ -101,5 +93,12 @@ void PropFileView::init(tgui::Group::Ptr layout, VariantWrapper *variant) { collisionsField->setValue(prop->getCollisionRect()); interactableTypeField->value->setSelectedItem(prop->getInteractableType()); interactableTypeField->setEnabled(prop->getHasInteractable()); + + propPreview->setProp(prop); + auto val = propView->getAtlasRect(); + if (val.has_value()) { + propPreview->setBox(val.value()); + } + addWidgets(layout); } diff --git a/src/editor/fileViews/roomFileView.cpp b/src/editor/fileViews/roomFileView.cpp index ed1e78c9..c064e314 100644 --- a/src/editor/fileViews/roomFileView.cpp +++ b/src/editor/fileViews/roomFileView.cpp @@ -1,4 +1,7 @@ #include "fileViews/roomFileView.hpp" + +#include + #include "TGUI/String.hpp" #include "TGUI/Widgets/CheckBox.hpp" #include "TGUI/Widgets/ComboBox.hpp" @@ -17,7 +20,6 @@ #include "widgets/propertiesBox.hpp" #include "widgets/propertyFields/fileField.hpp" #include "widgets/toolbox.hpp" -#include RoomFileView::RoomFileView() { RoomTool a; @@ -25,15 +27,13 @@ RoomFileView::RoomFileView() { HotkeyService &hks = Editor::instance->getHotkeyService(); roomView = RoomView::create(); - roomView->setSize({TextFormat("100%% - %d", RIGHT_PANEL_W), - TextFormat("100%% - %d", TOOLBOX_H)}); + roomView->setSize({TextFormat("100%% - %d", RIGHT_PANEL_W), TextFormat("100%% - %d", TOOLBOX_H)}); roomView->setPosition(0, TOOLBOX_H); Editor::instance->getGui().addUpdate(WorldView::asUpdatable(roomView)); widgetContainer.push_back(roomView); auto roomLayerGroup = tgui::Group::create(); - roomLayerGroup->setPosition(TextFormat("100%% - %d", RIGHT_PANEL_W), - LAYER_CHOOSE_H); + roomLayerGroup->setPosition(TextFormat("100%% - %d", RIGHT_PANEL_W), LAYER_CHOOSE_H); roomLayerGroup->setSize({ROOM_LAYER_W, ROOM_LAYER_H}); layerVisitor.group = roomLayerGroup; @@ -73,34 +73,28 @@ RoomFileView::RoomFileView() { auto props = PropertiesBox::create(); props->setSize({RIGHT_PANEL_W, "100%"}); - props->setPosition({TextFormat("100%% - %d", RIGHT_PANEL_W), - ROOM_LAYER_H + LAYER_CHOOSE_H}); + props->setPosition({TextFormat("100%% - %d", RIGHT_PANEL_W), ROOM_LAYER_H + LAYER_CHOOSE_H}); widthField = IntField::create(); - bindTranslation(widthField->label, "screen.project.roomview.mapwidth", - &tgui::Label::setText); - widthField->value->onValueChange([this](int value) { - Vector2 worldSize = - this->roomView->getRoom()->getTileMap()->getMaxWorldSize(); - worldSize.x = value; + bindTranslation(widthField->label, "screen.project.roomview.mapwidth", &tgui::Label::setText); + widthField->value->onValueChange([this](const auto &value) { + Vector2 worldSize = this->roomView->getRoom()->getTileMap()->getMaxWorldSize(); + worldSize.x = static_cast(value); this->roomView->getRoom()->getTileMap()->setWorldSize(worldSize); }); props->addIntField(widthField); heightField = IntField::create(); - bindTranslation(heightField->label, "screen.project.roomview.mapheight", - &tgui::Label::setText); - heightField->value->onValueChange([this](int value) { - Vector2 worldSize = - this->roomView->getRoom()->getTileMap()->getMaxWorldSize(); - worldSize.y = value; + bindTranslation(heightField->label, "screen.project.roomview.mapheight", &tgui::Label::setText); + heightField->value->onValueChange([this](const float &value) { + Vector2 worldSize = this->roomView->getRoom()->getTileMap()->getMaxWorldSize(); + worldSize.y = static_cast(value); this->roomView->getRoom()->getTileMap()->setWorldSize(worldSize); }); props->addIntField(heightField); tileSetField = FileField::create("", "..."); - bindTranslation(tileSetField->label, "screen.project.roomview.tileset_file", - &tgui::Label::setText); + bindTranslation(tileSetField->label, "screen.project.roomview.tileset_file", &tgui::Label::setText); tileSetField->pathFilters = {{"RPG++ TileSet", {"*.rtiles"}}}; tileSetField->callback = [this](const tgui::String &path) { auto room = this->roomView->getRoom(); @@ -110,14 +104,11 @@ RoomFileView::RoomFileView() { props->addFileField(tileSetField); musicFileField = FileField::create("", ""); - bindTranslation(musicFileField->label, - "screen.project.roomview.bg_music_file", - &tgui::Label::setText); + bindTranslation(musicFileField->label, "screen.project.roomview.bg_music_file", &tgui::Label::setText); musicFileField->setWidgetName("file"); musicFileField->pathFilters = {{"Music File", {"*.mp4", "*.ogg", "*.wav"}}}; musicFileField->callback = [this](const tgui::String &path) { - roomView->getRoom()->setMusicSource( - GetFileNameWithoutExt(path.toStdString().c_str())); + roomView->getRoom()->setMusicSource(GetFileNameWithoutExt(path.toStdString().c_str())); }; props->addFileField(musicFileField); @@ -131,51 +122,36 @@ RoomFileView::RoomFileView() { auto toolbox = Toolbox::create(); toolbox->getVerticalScrollbar()->setPolicy(tgui::Scrollbar::Policy::Never); - toolbox->getHorizontalScrollbar()->setPolicy( - tgui::Scrollbar::Policy::Never); + toolbox->getHorizontalScrollbar()->setPolicy(tgui::Scrollbar::Policy::Never); toolbox->setSize({TextFormat("100%% - %d", RIGHT_PANEL_W), TOOLBOX_H}); std::vector>> tools = { - {"room_tool.mouse", ToolboxItem{"tool", RoomTool::TOOL_NONE, - "Mouse", "tool_none.png"}}, - {"room_tool.pen", ToolboxItem{"tool", RoomTool::TOOL_PLACE, - "Place", "tool_place.png"}}, - {"room_tool.eraser", ToolboxItem{"tool", RoomTool::TOOL_ERASE, - "Erase", "tool_erase.png"}}, - {"room_tool.edit", ToolboxItem{"tool", RoomTool::TOOL_EDIT, - "Edit", "tool_edit.png"}}, + {"room_tool.mouse", ToolboxItem{"tool", RoomTool::TOOL_NONE, "Mouse", "tool_none.png"}}, + {"room_tool.pen", ToolboxItem{"tool", RoomTool::TOOL_PLACE, "Place", "tool_place.png"}}, + {"room_tool.eraser", ToolboxItem{"tool", RoomTool::TOOL_ERASE, "Erase", "tool_erase.png"}}, + {"room_tool.edit", ToolboxItem{"tool", RoomTool::TOOL_EDIT, "Edit", "tool_edit.png"}}, {"room_tool.set_spoint", - ToolboxItem{"tool", RoomTool::TOOL_STARTPOINT, "Start Point", - "tool_startpoint.png"}}}; + ToolboxItem{"tool", RoomTool::TOOL_STARTPOINT, "Start Point", "tool_startpoint.png"}}}; for (auto &[k, tool] : tools) { auto capturedTool = tool; toolbox->addTool(tool); - hotkeyEntries.push_back( - hks.registerHotkeyCallback(k, [this, capturedTool, toolbox]() { - if (fileViewFocused) - toolbox->selectTool(capturedTool); - })); + hotkeyEntries.push_back(hks.registerHotkeyCallback(k, [this, capturedTool, toolbox]() { + if (fileViewFocused) toolbox->selectTool(capturedTool); + })); } auto brushToggle = tgui::CheckBox::create(); - bindTranslation(brushToggle, - "screen.project.roomview.enable_brush", - &tgui::CheckBox::setText); - brushToggle->onChange( - [this](bool toggled) { roomView->setBrush(toggled); }); - auto brushToggleSize = - TOOLBOX_H - toolbox->getRenderer()->getPadding().getTop(); + bindTranslation(brushToggle, "screen.project.roomview.enable_brush", &tgui::CheckBox::setText); + brushToggle->onChange([this](bool toggled) { roomView->setBrush(toggled); }); + auto brushToggleSize = TOOLBOX_H - toolbox->getRenderer()->getPadding().getTop(); brushToggle->setSize({brushToggleSize, brushToggleSize}); toolbox->addWidget(brushToggle); - hotkeyEntries.push_back(hks.registerHotkeyCallback( - "room_tool.toggle_bm", [this, brushToggle]() { - if (fileViewFocused) - brushToggle->setChecked(!brushToggle->isChecked()); - })); + hotkeyEntries.push_back(hks.registerHotkeyCallback("room_tool.toggle_bm", [this, brushToggle]() { + if (fileViewFocused) brushToggle->setChecked(!brushToggle->isChecked()); + })); - toolbox->onItemClicked( - [this](ToolboxItem tool) { setRoomTool(tool); }); + toolbox->onItemClicked([this](ToolboxItem tool) { setRoomTool(tool); }); widgetContainer.push_back(toolbox); } @@ -185,8 +161,7 @@ void RoomFileView::setRoomTool(ToolboxItem tool) { roomView->setTool(tool.id); layerVisitor.tool = tool.id; layerVisitor.group->removeAllWidgets(); - mj::visit(layerVisitor, - static_cast(layerChoose->getSelectedItemIndex())); + mj::visit(layerVisitor, static_cast(layerChoose->getSelectedItemIndex())); } RoomFileView::~RoomFileView() { HotkeyService &hks = Editor::instance->getHotkeyService(); @@ -196,21 +171,18 @@ RoomFileView::~RoomFileView() { } void RoomFileView::init(tgui::Group::Ptr layout, VariantWrapper *variant) { - if (variant == nullptr) - return; + if (variant == nullptr) return; auto ptr = dynamic_cast *>(variant); auto room = ptr->get(); - if (room == nullptr) - return; + if (room == nullptr) return; roomView->setRoom(room); tileSetView->setTileSet(room->getTileMap()->getTileSet()); widthField->value->setValue(room->getTileMap()->getMaxWorldSize().x); heightField->value->setValue(room->getTileMap()->getMaxWorldSize().y); tileSetField->value->setText(room->getTileMap()->getTileSetSource()); - musicFileField->value->setText( - GetFileNameWithoutExt(room->getMusicSource().c_str())); + musicFileField->value->setText(GetFileNameWithoutExt(room->getMusicSource().c_str())); addWidgets(layout); } diff --git a/src/editor/fileViews/soundFileView.cpp b/src/editor/fileViews/soundFileView.cpp index da743080..61127c5a 100644 --- a/src/editor/fileViews/soundFileView.cpp +++ b/src/editor/fileViews/soundFileView.cpp @@ -1,15 +1,17 @@ #include "fileViews/soundFileView.hpp" + +#include +#include +#include +#include +#include + #include "editor.hpp" #include "raylib.h" #include "saveables/soundWrapper.hpp" #include "timeFormat.hpp" #include "updatable.hpp" #include "widgets/soundPlayer.hpp" -#include -#include -#include -#include -#include SoundFileView::SoundFileView() { auto topPanel = tgui::Panel::create(); @@ -25,8 +27,7 @@ SoundFileView::SoundFileView() { soundPlayer->setPosition(20, 36 + 20); soundPlayer->setSize({"100% - 40", 48}); - Editor::instance->getGui().addUpdate( - dynamic_pointer_cast(soundPlayer)); + Editor::instance->getGui().addUpdate(dynamic_pointer_cast(soundPlayer)); widgetContainer.push_back(topPanel); widgetContainer.push_back(soundPlayer); @@ -40,9 +41,8 @@ void SoundFileView::init(tgui::Group::Ptr layout, VariantWrapper *variant) { auto ptr = dynamic_cast *>(variant); auto sound = ptr->get(); - infoLabel->setText( - TextFormat("%s | Length: %s", GetFileName(sound->source.c_str()), - formatTime(GetMusicTimeLength(sound->sound)).c_str())); + infoLabel->setText(TextFormat("%s | Length: %s", GetFileName(sound->source.c_str()), + formatTime(GetMusicTimeLength(sound->sound)).c_str())); soundPlayer->setSound(sound); addWidgets(layout); diff --git a/src/editor/fileViews/tilesetFileView.cpp b/src/editor/fileViews/tilesetFileView.cpp index c28481d5..e55b53c0 100644 --- a/src/editor/fileViews/tilesetFileView.cpp +++ b/src/editor/fileViews/tilesetFileView.cpp @@ -1,4 +1,7 @@ #include "fileViews/tilesetFileView.hpp" + +#include + #include "TGUI/Widgets/Group.hpp" #include "bindTranslation.hpp" #include "editor.hpp" @@ -11,7 +14,6 @@ #include "widgets/propertiesBox.hpp" #include "widgets/propertyFields/fileField.hpp" #include "widgets/propertyFields/intField.hpp" -#include TileSetFileView::TileSetFileView() { TranslationService &ts = Editor::instance->getTranslations(); @@ -27,20 +29,15 @@ TileSetFileView::TileSetFileView() { props->setPosition({TextFormat("100%% - %d", RIGHT_PANEL_W), 0}); widthField = IntField::create(); - bindTranslation(widthField->label, "screen.project.tilesetview.tile_width", - &tgui::Label::setText); - widthField->value->onValueChange([this](int value) { - this->worldView->getTileSet()->setTileWidth(value); - }); + bindTranslation(widthField->label, "screen.project.tilesetview.tile_width", &tgui::Label::setText); + widthField->value->onValueChange( + [this](const float &value) { this->worldView->getTileSet()->setTileWidth(static_cast(value)); }); props->addIntField(widthField); heightField = IntField::create(); - bindTranslation(heightField->label, - "screen.project.tilesetview.tile_height", - &tgui::Label::setText); - heightField->value->onValueChange([this](int value) { - this->worldView->getTileSet()->setTileHeight(value); - }); + bindTranslation(heightField->label, "screen.project.tilesetview.tile_height", &tgui::Label::setText); + heightField->value->onValueChange( + [this](const float &value) { this->worldView->getTileSet()->setTileHeight(static_cast(value)); }); props->addButton("Square Tiles", [this] { auto tileset = this->worldView->getTileSet(); @@ -56,8 +53,7 @@ TileSetFileView::TileSetFileView() { props->addIntField(heightField); textureFile = FileField::create("", "..."); - bindTranslation(textureFile->label, "screen.project.tilesetview.texture", - &tgui::Label::setText); + bindTranslation(textureFile->label, "screen.project.tilesetview.texture", &tgui::Label::setText); textureFile->pathFilters = {{ {"Images", {"*.png", "*.jpg"}}, }}; diff --git a/src/editor/project.cpp b/src/editor/project.cpp index 59e8aab8..723d551a 100644 --- a/src/editor/project.cpp +++ b/src/editor/project.cpp @@ -1,14 +1,9 @@ #include "project.hpp" -#include "conversion.hpp" -#include "dialogue.hpp" -#include "dialogueParser.hpp" -#include "editor.hpp" -#include "gamedata.hpp" -#include "interactable.hpp" -#include "room.hpp" -#include "screens/projectScreen.hpp" -#include "services/fileSystemService.hpp" -#include "tileset.hpp" + +#include + +#include +#include #include #include #include @@ -17,23 +12,24 @@ #include #include #include -#include +#include #include #include -#ifdef _WIN64 +#include "conversion.hpp" +#include "dialogue.hpp" +#include "dialogueParser.hpp" +#include "editor.hpp" +#include "gamedata.hpp" +#include "interactable.hpp" +#include "room.hpp" +#include "screens/projectScreen.hpp" +#include "services/fileSystemService.hpp" +#include "tileset.hpp" -#include "fix_win32_compatibility.h" -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include +#ifdef _WIN32 + +#include #else @@ -55,26 +51,54 @@ Project::Project(const std::string &path) { char *jsonContent = LoadFileText(path.c_str()); json j = json::parse(jsonContent); - this->projectTitle = j.at("title"); + programSet.projectTitle = j.value("title", ""); + programSet.windowSize = {j.value("windowSize", json::array({640, 480}))[0], + j.value("windowSize", json::array({640, 480}))[1]}; + programSet.projectVersion = j.value("version", ""); + programSet.programIconPath = j.value("programIcon", ""); + programSet.windowResizeableFlag = j.value("windowResizeable", false); + programSet.windowStateFlag = j.value("windowState", 0); + programSet.targetFPS = j.value("targetFPS", 60); + + gameSet.defaultRoomPath = j.value("defaultRoom", ""); + gameSet.playerActorPath = j.value("playerActor", ""); + gameSet.tileSize = j.value("tileSize", 16); + gameSet.debugDraw = j.value("debugDraw", false); + gameSet.exportImageScales = j.value("exportImageScales", std::vector{1}); + gameSet.exportFontSizes = j.value("exportFontSizes", std::vector{13}); ChangeDirectory(projectPath.c_str()); UnloadFileText(jsonContent); } -std::string Project::create(const std::string &dirPath, - const std::string &title) { - json j = json::object(); - j["title"] = title; +std::string Project::create(const std::string &dirPath, const std::string &title) { + Project p; + p.getProgramSettings().projectTitle = title; + json j = p.toJson(); std::string fileContent = j.dump(); std::filesystem::path filePath = dirPath; filePath /= "proj.rpgpp"; SaveFileText(filePath.u8string().c_str(), fileContent.c_str()); - MakeDirectory( - std::filesystem::path(dirPath).append("tilesets").u8string().c_str()); - MakeDirectory( - std::filesystem::path(dirPath).append("maps").u8string().c_str()); + for (int i = 0; i < FILETYPE_MAX; i++) { + EngineFileType fileType = static_cast(i); + + if (fileType != EngineFileType::FILE_EMPTY) { + std::string dirName = TextToLower(Editor::instance->getFs().getTypeName(fileType).c_str()); + + std::string typeDirPath = TextFormat("%s/%s", dirPath.c_str(), dirName.c_str()); + + std::string defaultDirName = TextFormat( + "%s/resources/defaults/%s", Editor::instance->getFs().getEditorBaseDir().c_str(), dirName.c_str()); + + if (DirectoryExists(defaultDirName.c_str())) { + std::filesystem::copy(defaultDirName, typeDirPath, std::filesystem::copy_options::recursive); + } else { + MakeDirectory(std::filesystem::path(dirPath).append(dirName).u8string().c_str()); + } + } + } return filePath.u8string(); } @@ -82,25 +106,41 @@ std::string Project::create(const std::string &dirPath, void Project::openProject(const tgui::String &filePath, bool forceSwitch) { Editor::instance->setProject(filePath.toStdString()); Editor::instance->getRecentProjectService().enqueue(filePath.toStdString()); - Editor::instance->getGui().setScreen( - std::make_unique(), forceSwitch); + Editor::instance->getGui().setScreen(std::make_unique(), forceSwitch); } json Project::toJson() { json j = json::object(); - j["title"] = projectTitle; + + j["title"] = programSet.projectTitle; + j["windowSize"] = {programSet.windowSize.x, programSet.windowSize.y}; + j["version"] = programSet.projectVersion; + j["programIcon"] = programSet.programIconPath; + j["windowResizeable"] = programSet.windowResizeableFlag; + j["windowState"] = programSet.windowStateFlag; + j["targetFPS"] = programSet.targetFPS; + + j["defaultRoom"] = gameSet.defaultRoomPath; + j["tileSize"] = gameSet.tileSize; + j["playerActor"] = gameSet.playerActorPath; + j["debugDraw"] = gameSet.debugDraw; + j["exportImageScales"] = gameSet.exportImageScales; + j["exportFontSizes"] = gameSet.exportFontSizes; return j; } -std::string &Project::getTitle() { return projectTitle; } +ProjectProgramSettings &Project::getProgramSettings() { return programSet; } + +ProjectGameSettings &Project::getGameSettings() { return gameSet; } std::string &Project::getBasePath() { return projectPath; } std::vector Project::getPaths(EngineFileType fileType) { std::filesystem::path subdir = projectPath; - subdir /= - TextToLower(Editor::instance->getFs().getTypeName(fileType).c_str()); + subdir /= TextToLower(Editor::instance->getFs().getTypeName(fileType).c_str()); + + auto &extensions = Editor::instance->getFs().getTypeExtensions(fileType); assert(subdir.string().empty() == false && "directory path is empty"); @@ -108,7 +148,14 @@ std::vector Project::getPaths(EngineFileType fileType) { std::vector vec = {}; for (int i = 0; i < pathList.count; i++) { - vec.emplace_back(pathList.paths[i]); + std::string fullPath = pathList.paths[i]; + std::string fileExt = GetFileExtension(fullPath.c_str()); + for (auto &j : extensions) { + if (j == fileExt) { + vec.emplace_back(fullPath); + break; + } + } } UnloadDirectoryFiles(pathList); @@ -116,11 +163,9 @@ std::vector Project::getPaths(EngineFileType fileType) { return vec; } -std::string Project::getResourcePath(EngineFileType fileType, - const std::string &fileName) { +std::string Project::getResourcePath(EngineFileType fileType, const std::string &fileName) { std::filesystem::path subdir = projectPath; - subdir /= - TextToLower(Editor::instance->getFs().getTypeName(fileType).c_str()); + subdir /= TextToLower(Editor::instance->getFs().getTypeName(fileType).c_str()); subdir /= fileName; return subdir.string(); @@ -130,19 +175,28 @@ std::map Project::getInteractableNames() { std::map map{}; // built-in interactables - std::filesystem::path interactablesDir = - Editor::instance->getFs().getEditorBaseDir(); - interactablesDir /= "resources"; - interactablesDir /= "interactables"; + std::filesystem::path builtinInteractablesDir = Editor::instance->getFs().getEditorBaseDir(); + builtinInteractablesDir /= "resources"; + builtinInteractablesDir /= "interactables"; - auto list = LoadDirectoryFiles(interactablesDir.u8string().c_str()); - for (int i = 0; i < list.count; i++) { - std::string intPath = list.paths[i]; + auto builtinList = LoadDirectoryFiles(builtinInteractablesDir.u8string().c_str()); + for (int i = 0; i < builtinList.count; i++) { + std::string intPath = builtinList.paths[i]; Interactable inter(intPath); map[intPath.c_str()] = inter.getDisplayTitle(); } - UnloadDirectoryFiles(list); + UnloadDirectoryFiles(builtinList); + + auto userList = LoadDirectoryFiles("interactables/"); + for (int i = 0; i < userList.count; i++) { + std::string intPath = userList.paths[i]; + Interactable inter(intPath); + + map[intPath.c_str()] = inter.getDisplayTitle(); + } + + UnloadDirectoryFiles(userList); return map; } @@ -156,8 +210,20 @@ std::vector Project::getPropsNames() { } GameData Project::generateStruct() { + pugi::xml_document xmlDoc; + auto result = xmlDoc.load_string("Hello RED!"); + if (result) { + for (auto item : xmlDoc.child("text").children()) { + std::cout << item.name() << " : "; + std::cout << item.text().as_string(); + std::cout << std::endl; + } + } + GameData data; - data.title = projectTitle; + data.title = programSet.projectTitle; + data.programSet = programSet; + data.gameSet = gameSet; for (auto tileSetPath : getPaths(EngineFileType::FILE_TILESET)) { TileSet tileSet(tileSetPath); @@ -165,22 +231,18 @@ GameData Project::generateStruct() { Image image = LoadImageFromTexture(texture); int fileSize = 0; - std::string fileType = - GetFileExtension(tileSet.getTextureSource().c_str()); - unsigned char *imageData = - ExportImageToMemory(image, fileType.c_str(), &fileSize); + std::string fileType = GetFileExtension(tileSet.getTextureSource().c_str()); + unsigned char *imageData = ExportImageToMemory(image, fileType.c_str(), &fileSize); TileSetBin tileSetBin; tileSetBin.name = GetFileName(tileSetPath.c_str()); - tileSetBin.extension = - GetFileExtension(tileSet.getTextureSource().c_str()); + tileSetBin.extension = GetFileExtension(tileSet.getTextureSource().c_str()); for (int i = 0; i < fileSize; i++) { tileSetBin.image.push_back(*imageData); imageData++; } tileSetBin.tileSize = - IVector{static_cast(tileSet.getTileSize().x), - static_cast(tileSet.getTileSize().y)}; + IVector{static_cast(tileSet.getTileSize().x), static_cast(tileSet.getTileSize().y)}; tileSetBin.dataSize = fileSize; data.tilesets[GetFileName(tileSetPath.c_str())] = tileSetBin; @@ -212,10 +274,8 @@ GameData Project::generateStruct() { Vector2 atlasPos = tile.getAtlasTile().getAtlasCoords(); Vector2 worldPos = tile.getWorldCoords(); - IVector intAtlas = IVector{static_cast(atlasPos.x), - static_cast(atlasPos.y)}; - IVector intWorld = IVector{static_cast(worldPos.x), - static_cast(worldPos.y)}; + IVector intAtlas = IVector{static_cast(atlasPos.x), static_cast(atlasPos.y)}; + IVector intWorld = IVector{static_cast(worldPos.x), static_cast(worldPos.y)}; TileBin tileBin; tileBin.atlasPos = intAtlas; @@ -227,8 +287,8 @@ GameData Project::generateStruct() { map.reset(); std::unique_ptr room = std::make_unique(roomPath); - roomBin.startPoint = IVector{static_cast(room->getStartTile().x), - static_cast(room->getStartTile().y)}; + roomBin.startPoint = + IVector{static_cast(room->getStartTile().x), static_cast(room->getStartTile().y)}; for (auto [pos, obj] : room->getCollisions().getObjects()) { IVector intVec; intVec.x = static_cast(pos.x); @@ -242,8 +302,23 @@ GameData Project::generateStruct() { intBin.type = interactable->getType(); intBin.onTouch = interactable->isOnTouch(); - intBin.propsCbor = - nlohmann::json::to_cbor(interactable->getProps()); + // add missing props to the interactable in the map + for (auto &item : getInteractableNames()) { + std::string itemType = GetFileNameWithoutExt(item.first.c_str()); + if (itemType == interactable->getType()) { + Interactable itemInteractable(item.first); + + for (auto prop : itemInteractable.getProps().items()) { + if (!interactable->getProps().contains(prop.key())) { + interactable->getProps().push_back({prop.key(), prop.value()}); + } + } + + break; + } + } + + intBin.propsCbor = nlohmann::json::to_cbor(interactable->getProps()); roomBin.interactables.push_back(intBin); } @@ -252,8 +327,26 @@ GameData Project::generateStruct() { pBin.name = prop->getSourcePath(); pBin.tilePos = fromVector2(prop->getWorldTilePos()); - pBin.propsCbor = - nlohmann::json::to_cbor(prop->getInteractable()->getProps()); + auto *interactable = prop->getInteractable(); + + // add missing props to the interactable in the prop + for (auto &item : getInteractableNames()) { + std::string itemType = GetFileNameWithoutExt(item.first.c_str()); + if (itemType == interactable->getType()) { + Interactable itemInteractable(item.first); + + for (auto prop : itemInteractable.getProps().items()) { + if (!interactable->getProps().contains(prop.key())) { + interactable->getProps().push_back({prop.key(), prop.value()}); + } + } + + break; + } + } + + pBin.propsCbor = nlohmann::json::to_cbor(prop->getInteractable()->getProps()); + roomBin.props.push_back(pBin); } for (auto &[aName, actor] : room->getActors().getActors()) { @@ -261,8 +354,14 @@ GameData Project::generateStruct() { aBin.name = aName; aBin.source = actor->getSourcePath(); aBin.tilePos = - IVector{static_cast(actor->getTilePosition().x), - static_cast(actor->getTilePosition().y)}; + IVector{static_cast(actor->getTilePosition().x), static_cast(actor->getTilePosition().y)}; + + if (actor->hasInteractable()) { + aBin.intType = actor->getInteractable()->getType(); + aBin.propsCbor = nlohmann::json::to_cbor(actor->getInteractable()->getProps()); + } else { + aBin.intType = ""; + } roomBin.actors.push_back(aBin); } roomBin.musicSource = room->getMusicSource(); @@ -279,18 +378,13 @@ GameData Project::generateStruct() { actorBin.tileSetName = GetFileName(actor->getTileSetSource().c_str()); Rectangle collisionRect = actor->getCollisionRect(); - actorBin.collision = IRect{static_cast(collisionRect.x), - static_cast(collisionRect.y), - static_cast(collisionRect.width), - static_cast(collisionRect.height)}; - std::array, 8> animations = - actor->getAnimationsRaw(); + actorBin.collision = IRect{static_cast(collisionRect.x), static_cast(collisionRect.y), + static_cast(collisionRect.width), static_cast(collisionRect.height)}; + std::array, 8> animations = actor->getAnimationsRaw(); for (int i = 0; i < 8; i++) { - for (int frameIndex = 0; frameIndex < animations[i].size(); - frameIndex++) { + for (int frameIndex = 0; frameIndex < animations[i].size(); frameIndex++) { Vector2 vec = animations[i][frameIndex]; - IVector intVec = - IVector{static_cast(vec.x), static_cast(vec.y)}; + IVector intVec = IVector{static_cast(vec.x), static_cast(vec.y)}; actorBin.animations[i].push_back(intVec); } @@ -304,6 +398,11 @@ GameData Project::generateStruct() { DialogueBin diag = dialogue.getData(); diag.title = GetFileNameWithoutExt(diagPath.c_str()); + for (auto &line : diag.lines) { + for (auto &option : line.options) { + option.nextDialogue = GetFileNameWithoutExt(option.nextDialogue.c_str()); + } + } data.dialogues[GetFileNameWithoutExt(diagPath.c_str())] = diag; } @@ -314,8 +413,7 @@ GameData Project::generateStruct() { int fileSize = 0; - unsigned char *imgData = ExportImageToMemory( - img, GetFileExtension(imagePath.c_str()), &fileSize); + unsigned char *imgData = ExportImageToMemory(img, GetFileExtension(imagePath.c_str()), &fileSize); for (int i = 0; i < fileSize; i++) { bin.data.push_back(*imgData); imgData++; @@ -328,6 +426,20 @@ GameData Project::generateStruct() { } for (auto fontPath : getPaths(EngineFileType::FILE_FONT)) { + FontBin fontBin; + + int dataSize = 0; + auto fileData = LoadFileData(fontPath.c_str(), &dataSize); + + for (int i = 0; i < dataSize; i++) { + fontBin.data.push_back(fileData[i]); + } + + fontBin.ext = GetFileExtension(fontPath.c_str()); + fontBin.dataSize = dataSize; + data.fonts[GetFileNameWithoutExt(fontPath.c_str())] = fontBin; + + UnloadFileData(fileData); } for (auto soundPath : getPaths(EngineFileType::FILE_SOUND)) { @@ -369,15 +481,12 @@ GameData Project::generateStruct() { PropBin bin; bin.name = GetFileNameWithoutExt(propPath.c_str()); - bin.atlasRect = IRect{static_cast(prop.getAtlasRect().x), - static_cast(prop.getAtlasRect().y), - static_cast(prop.getAtlasRect().width), - static_cast(prop.getAtlasRect().height)}; + bin.atlasRect = + IRect{static_cast(prop.getAtlasRect().x), static_cast(prop.getAtlasRect().y), + static_cast(prop.getAtlasRect().width), static_cast(prop.getAtlasRect().height)}; bin.collisionRect = - IRect{static_cast(prop.getCollisionRect().x), - static_cast(prop.getCollisionRect().y), - static_cast(prop.getCollisionRect().width), - static_cast(prop.getCollisionRect().height)}; + IRect{static_cast(prop.getCollisionRect().x), static_cast(prop.getCollisionRect().y), + static_cast(prop.getCollisionRect().width), static_cast(prop.getCollisionRect().height)}; bin.imagePath = std::string(prop.getImagePath()); bin.hasInteractable = prop.getHasInteractable(); if (prop.getInteractable() == nullptr) { @@ -389,9 +498,8 @@ GameData Project::generateStruct() { data.props.push_back(bin); } - // built in insteractables - std::filesystem::path interactablesDir = - Editor::instance->getFs().getEditorBaseDir(); + // built in interactables + std::filesystem::path interactablesDir = Editor::instance->getFs().getEditorBaseDir(); interactablesDir /= "resources"; interactablesDir /= "interactables"; @@ -405,15 +513,28 @@ GameData Project::generateStruct() { bin.scriptPath = inter.getScriptSourcePath(); bin.props = nlohmann::json::to_cbor(inter.getProps()); - printf("%s \n", bin.typeName.c_str()); - data.interactables[inter.getType()] = bin; } UnloadDirectoryFiles(list); - // scripts - std::filesystem::path scriptsDir = - Editor::instance->getFs().getEditorBaseDir(); + // user interactables + auto userList = LoadDirectoryFiles("interactables/"); + for (int i = 0; i < userList.count; i++) { + std::string intPath = userList.paths[i]; + Interactable inter(intPath); + + InteractableBin bin; + bin.typeName = inter.getType(); + bin.scriptPath = inter.getScriptSourcePath(); + bin.props = nlohmann::json::to_cbor(inter.getProps()); + + data.interactables[inter.getType()] = bin; + } + + UnloadDirectoryFiles(userList); + + // built-in scripts + std::filesystem::path scriptsDir = Editor::instance->getFs().getEditorBaseDir(); scriptsDir /= "resources"; scriptsDir /= "scripts"; auto scriptsList = LoadDirectoryFiles(scriptsDir.u8string().c_str()); @@ -441,6 +562,18 @@ GameData Project::generateStruct() { } UnloadDirectoryFiles(scriptsList); + auto userScriptsList = LoadDirectoryFiles("scripts/"); + for (int i = 0; i < userScriptsList.count; i++) { + std::string scriptPath = userScriptsList.paths[i]; + auto scriptText = LoadFileText(scriptPath.c_str()); + + ScriptBin bin; + bin.bytecode = scriptText; + + data.scripts[TextFormat("scripts/%s", GetFileName(scriptPath.c_str()))] = bin; + UnloadFileText(scriptText); + } + return data; } @@ -471,67 +604,34 @@ void Project::runProject() { intepreterPath /= "luajit"; libDest /= "rpgpplua.so"; - std::filesystem::copy_file( - libPath, libDest, std::filesystem::copy_options::overwrite_existing); + std::filesystem::copy_file(libPath, libDest, std::filesystem::copy_options::overwrite_existing); ChangeDirectory(projectPath.c_str()); - std::string cmdLine = TextFormat( - "%s -l rpgpplua %s", intepreterPath.c_str(), scriptPath.c_str()); + std::string cmdLine = TextFormat("%s -l rpgpplua %s", intepreterPath.c_str(), scriptPath.c_str()); printf("%s \n", cmdLine.c_str()); char buffer[256]; FILE *stream; - stream = popen(TextFormat("%s -l rpgpplua %s", intepreterPath.c_str(), - scriptPath.c_str()), - "r"); + stream = popen(TextFormat("%s -l rpgpplua %s", intepreterPath.c_str(), scriptPath.c_str()), "r"); #endif -#ifdef _WIN64 +#ifdef _WIN32 intepreterPath /= "luajit.exe"; const std::filesystem::path rpgppDllPath = "rpgpplua.dll"; libPath /= rpgppDllPath; libDest /= rpgppDllPath; - std::filesystem::copy_file( - libPath, libDest, std::filesystem::copy_options::overwrite_existing); + std::filesystem::copy_file(libPath, libDest, std::filesystem::copy_options::overwrite_existing); ChangeDirectory(projectPath.c_str()); // note: compared to linux, you have to add .string() to every single one of // these paths. - std::string cmdLine = - TextFormat("%s -l rpgpplua %s", intepreterPath.string().c_str(), - scriptPath.string().c_str()); - - HANDLE outFile = nullptr; - - outFile = CreateFile("playtest.log", GENERIC_WRITE, FILE_SHARE_WRITE, NULL, - OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL); - - PROCESS_INFORMATION piProcInfo; - STARTUPINFO siStartInfo; - - SetStdHandle(STD_OUTPUT_HANDLE, outFile); - ZeroMemory(&piProcInfo, sizeof(PROCESS_INFORMATION)); + std::string cmdLine = TextFormat("%s -l rpgpplua %s", intepreterPath.string().c_str(), scriptPath.string().c_str()); - ZeroMemory(&siStartInfo, sizeof(STARTUPINFO)); - siStartInfo.cb = sizeof(STARTUPINFO); - siStartInfo.hStdOutput = outFile; - siStartInfo.dwFlags |= STARTF_USESTDHANDLES; - - bool success = CreateProcess(NULL, cmdLine.data(), NULL, NULL, true, 0, - NULL, NULL, &siStartInfo, &piProcInfo); - - if (!success) { - printf("Child process doesn't work. \n"); - } else { - CloseHandle(piProcInfo.hProcess); - CloseHandle(piProcInfo.hThread); - - CloseHandle(outFile); - } + WinRunWithLog("playtest.log", cmdLine); #endif } @@ -545,57 +645,28 @@ void Project::buildProject() { serializeDataToFile(binPath.u8string(), bin); // Copy base game file - std::filesystem::path baseGamePath = - Editor::instance->getFs().getEditorBaseDir(); + std::filesystem::path baseGamePath = Editor::instance->getFs().getEditorBaseDir(); std::filesystem::path resultPath = projectPath; -#ifdef _WIN64 +#ifdef _WIN32 baseGamePath /= "game.exe"; - resultPath /= TextFormat("%s.exe", projectTitle.c_str()); + resultPath /= TextFormat("%s.exe", programSet.projectTitle.c_str()); #else baseGamePath /= "game"; - resultPath /= projectTitle; + resultPath /= programSet.projectTitle; #endif try { - std::filesystem::copy( - baseGamePath, resultPath, - std::filesystem::copy_options::overwrite_existing); + std::filesystem::copy(baseGamePath, resultPath, std::filesystem::copy_options::overwrite_existing); } catch (const std::exception &) { printf("failed to copy file, aborting...\n"); return; } -#ifdef _WIN64 - - HANDLE outFile = nullptr; - - outFile = CreateFile("build.log", GENERIC_WRITE, FILE_SHARE_WRITE, NULL, - OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL); +#ifdef _WIN32 - PROCESS_INFORMATION piProcInfo; - STARTUPINFO siStartInfo; - - ZeroMemory(&piProcInfo, sizeof(PROCESS_INFORMATION)); - - ZeroMemory(&siStartInfo, sizeof(STARTUPINFO)); - siStartInfo.cb = sizeof(STARTUPINFO); - siStartInfo.hStdOutput = outFile; - siStartInfo.dwFlags |= STARTF_USESTDHANDLES; - - bool success = - CreateProcess(NULL, resultPath.string().data(), NULL, NULL, true, 0, - NULL, NULL, &siStartInfo, &piProcInfo); - - if (!success) { - printf("Child process could not be created.. \n"); - } else { - CloseHandle(piProcInfo.hProcess); - CloseHandle(piProcInfo.hThread); - - CloseHandle(outFile); - } + WinRunWithLog("build.log", resultPath.string().data()); #else @@ -606,7 +677,7 @@ void Project::buildProject() { dup2(fd, STDOUT_FILENO); - execl(resultPath.c_str(), NULL); + execl(resultPath.c_str(), ""); } else if (pid > 0) { printf("Started the game.. \n"); wait(0); diff --git a/src/editor/projectFile.cpp b/src/editor/projectFile.cpp index 9ea55991..acbf75ab 100644 --- a/src/editor/projectFile.cpp +++ b/src/editor/projectFile.cpp @@ -1,4 +1,9 @@ #include "projectFile.hpp" + +#include +#include +#include + #include "TGUI/Widgets/Group.hpp" #include "fileViews/emptyView.hpp" #include "fileViews/fileView.hpp" @@ -6,14 +11,10 @@ #include "services/fileSystemService.hpp" #include "tileset.hpp" #include "variant.hpp" -#include -#include -#include ProjectFile::ProjectFile() { view = std::make_unique(); } -ProjectFile::ProjectFile(std::unique_ptr view, - std::unique_ptr variant, +ProjectFile::ProjectFile(std::unique_ptr view, std::unique_ptr variant, EngineFileType fileType, bool isSaveable) { this->view = std::move(view); this->variant = std::move(variant); @@ -21,9 +22,7 @@ ProjectFile::ProjectFile(std::unique_ptr view, this->isSaveable = isSaveable; } -void ProjectFile::setFilePath(const std::string &filePath) { - this->filePath = filePath; -} +void ProjectFile::setFilePath(const std::string &filePath) { this->filePath = filePath; } std::string &ProjectFile::getFilePath() { return filePath; } @@ -35,13 +34,10 @@ void ProjectFile::initUi(tgui::Group::Ptr group) { } } -void ProjectFile::addWidgets(tgui::Group::Ptr layout) { - view->addWidgets(layout); -} +void ProjectFile::addWidgets(tgui::Group::Ptr layout) { view->addWidgets(layout); } void ProjectFile::saveFile(const std::string &path) { - if (!isSaveable) - return; + if (!isSaveable) return; auto saveable = variant->toSaveable(); json j = saveable->dumpJson(); diff --git a/src/editor/projectFileVisitor.cpp b/src/editor/projectFileVisitor.cpp index 09a0b4d5..4410d951 100644 --- a/src/editor/projectFileVisitor.cpp +++ b/src/editor/projectFileVisitor.cpp @@ -1,18 +1,23 @@ #include "projectFileVisitor.hpp" +#include +#include + #include "actor.hpp" #include "dialogue.hpp" #include "fileViews/actorFileView.hpp" -#include "fileViews/codeFileView.hpp" #include "fileViews/dialogueFileView.hpp" #include "fileViews/emptyView.hpp" #include "fileViews/fileView.hpp" #include "fileViews/fontFileView.hpp" #include "fileViews/imageFileView.hpp" +#include "fileViews/interactableFileView.hpp" #include "fileViews/propFileView.hpp" #include "fileViews/roomFileView.hpp" #include "fileViews/soundFileView.hpp" #include "fileViews/tilesetFileView.hpp" +#include "gamedata.hpp" +#include "interactable.hpp" #include "projectFile.hpp" #include "room.hpp" #include "saveables/fontWrapper.hpp" @@ -20,10 +25,9 @@ #include "saveables/soundWrapper.hpp" #include "scriptFile.h" #include "services/fileSystemService.hpp" +#include "tilemap.hpp" #include "tileset.hpp" #include "variant.hpp" -#include -#include ProjectFileVisitor::ProjectFileVisitor() { funcs[static_cast(EngineFileType::FILE_TILESET)] = tilesetView; @@ -37,109 +41,86 @@ ProjectFileVisitor::ProjectFileVisitor() { funcs[static_cast(EngineFileType::FILE_FONT)] = fontView; funcs[static_cast(EngineFileType::FILE_SOUND)] = soundView; funcs[static_cast(EngineFileType::FILE_MUSIC)] = musicView; + funcs[static_cast(EngineFileType::FILE_INTERACTABLE)] = interactableView; } -std::unique_ptr -ProjectFileVisitor::visit(EngineFileType fileType, const std::string &path) { +std::unique_ptr ProjectFileVisitor::visit(EngineFileType fileType, const std::string &path) { if (funcs.at(static_cast(fileType)) == nullptr) { return emptyView(path); } return funcs[static_cast(fileType)](path); } -std::unique_ptr -ProjectFileVisitor::emptyView(const std::string &path) { +std::unique_ptr ProjectFileVisitor::emptyView(const std::string &path) { return std::make_unique(); } -std::unique_ptr -ProjectFileVisitor::tilesetView(const std::string &path) { +std::unique_ptr ProjectFileVisitor::tilesetView(const std::string &path) { std::unique_ptr view = std::make_unique(); - std::unique_ptr variant = - std::make_unique>(new TileSet(path)); - return std::make_unique(std::move(view), std::move(variant), - EngineFileType::FILE_TILESET); + std::unique_ptr variant = std::make_unique>(new TileSet(path)); + return std::make_unique(std::move(view), std::move(variant), EngineFileType::FILE_TILESET); } -std::unique_ptr -ProjectFileVisitor::roomView(const std::string &path) { +std::unique_ptr ProjectFileVisitor::roomView(const std::string &path) { std::unique_ptr view = std::make_unique(); std::unique_ptr variant = - std::make_unique>(new Room(path)); - return std::make_unique(std::move(view), std::move(variant), - EngineFileType::FILE_MAP); + std::make_unique>(new Room(path, _RPGPP_TILESIZE * RPGPP_DRAW_MULTIPLIER, false)); + return std::make_unique(std::move(view), std::move(variant), EngineFileType::FILE_MAP); } -std::unique_ptr -ProjectFileVisitor::codeView(const std::string &path) { +std::unique_ptr ProjectFileVisitor::codeView(const std::string &path) { std::unique_ptr view = std::make_unique(); - std::unique_ptr variant = - std::make_unique>(new ScriptFile(path)); - auto res = std::make_unique( - std::move(view), std::move(variant), EngineFileType::FILE_SCRIPT); + std::unique_ptr variant = std::make_unique>(new ScriptFile(path)); + auto res = std::make_unique(std::move(view), std::move(variant), EngineFileType::FILE_SCRIPT); res->isEmpty = true; return std::move(res); } -std::unique_ptr -ProjectFileVisitor::dialogueView(const std::string &path) { +std::unique_ptr ProjectFileVisitor::dialogueView(const std::string &path) { std::unique_ptr view = std::make_unique(); - std::unique_ptr variant = - std::make_unique>(new Dialogue(path)); - return std::make_unique(std::move(view), std::move(variant), - EngineFileType::FILE_DIALOGUE); + std::unique_ptr variant = std::make_unique>(new Dialogue(path)); + return std::make_unique(std::move(view), std::move(variant), EngineFileType::FILE_DIALOGUE); } -std::unique_ptr -ProjectFileVisitor::actorView(const std::string &path) { +std::unique_ptr ProjectFileVisitor::actorView(const std::string &path) { std::unique_ptr view = std::make_unique(); - std::unique_ptr variant = - std::make_unique>(new Actor(path)); - return std::make_unique(std::move(view), std::move(variant), - EngineFileType::FILE_ACTOR); + std::unique_ptr variant = std::make_unique>(new Actor(path)); + return std::make_unique(std::move(view), std::move(variant), EngineFileType::FILE_ACTOR); } -std::unique_ptr -ProjectFileVisitor::propView(const std::string &path) { +std::unique_ptr ProjectFileVisitor::propView(const std::string &path) { std::unique_ptr view = std::make_unique(); - std::unique_ptr variant = - std::make_unique>(new Prop(path)); - return std::make_unique(std::move(view), std::move(variant), - EngineFileType::FILE_PROP); + std::unique_ptr variant = std::make_unique>(new Prop(path)); + return std::make_unique(std::move(view), std::move(variant), EngineFileType::FILE_PROP); } -std::unique_ptr -ProjectFileVisitor::imageView(const std::string &path) { +std::unique_ptr ProjectFileVisitor::imageView(const std::string &path) { std::unique_ptr view = std::make_unique(); - std::unique_ptr variant = - std::make_unique>(new ImageWrapper(path)); - return std::make_unique(std::move(view), std::move(variant), - EngineFileType::FILE_IMAGE, false); + std::unique_ptr variant = std::make_unique>(new ImageWrapper(path)); + return std::make_unique(std::move(view), std::move(variant), EngineFileType::FILE_IMAGE, false); } -std::unique_ptr -ProjectFileVisitor::fontView(const std::string &path) { +std::unique_ptr ProjectFileVisitor::fontView(const std::string &path) { std::unique_ptr view = std::make_unique(); - std::unique_ptr variant = - std::make_unique>(new FontWrapper(path)); - return std::make_unique(std::move(view), std::move(variant), - EngineFileType::FILE_FONT, false); + std::unique_ptr variant = std::make_unique>(new FontWrapper(path)); + return std::make_unique(std::move(view), std::move(variant), EngineFileType::FILE_FONT, false); } -std::unique_ptr -ProjectFileVisitor::soundView(const std::string &path) { +std::unique_ptr ProjectFileVisitor::soundView(const std::string &path) { std::unique_ptr view = std::make_unique(); - std::unique_ptr variant = - std::make_unique>(new SoundWrapper(path)); - return std::make_unique(std::move(view), std::move(variant), - EngineFileType::FILE_SOUND, false); + std::unique_ptr variant = std::make_unique>(new SoundWrapper(path)); + return std::make_unique(std::move(view), std::move(variant), EngineFileType::FILE_SOUND, false); } -std::unique_ptr -ProjectFileVisitor::musicView(const std::string &path) { +std::unique_ptr ProjectFileVisitor::musicView(const std::string &path) { std::unique_ptr view = std::make_unique(); - std::unique_ptr variant = - std::make_unique>(new SoundWrapper(path)); - return std::make_unique(std::move(view), std::move(variant), - EngineFileType::FILE_MUSIC, false); + std::unique_ptr variant = std::make_unique>(new SoundWrapper(path)); + return std::make_unique(std::move(view), std::move(variant), EngineFileType::FILE_MUSIC, false); +} + +std::unique_ptr ProjectFileVisitor::interactableView(const std::string &path) { + std::unique_ptr view = std::make_unique(); + std::unique_ptr variant = std::make_unique>(new Interactable(path)); + auto res = std::make_unique(std::move(view), std::move(variant), EngineFileType::FILE_INTERACTABLE); + return std::move(res); } diff --git a/src/editor/roomLayerViewVisitor.cpp b/src/editor/roomLayerViewVisitor.cpp index 6c17b0fe..3734db97 100644 --- a/src/editor/roomLayerViewVisitor.cpp +++ b/src/editor/roomLayerViewVisitor.cpp @@ -11,6 +11,7 @@ #include "TGUI/Widgets/Label.hpp" #include "actor.hpp" #include "editor.hpp" +#include "interactable.hpp" #include "services/fileSystemService.hpp" #include "views/worldView.hpp" #include "widgets/propertiesBox.hpp" @@ -20,6 +21,7 @@ RoomLayerViewVisitor::RoomLayerViewVisitor() { tileSetView->setSize({"100%", "100%"}); interactableChoose = tgui::ComboBox::create(); + interactableChoose->setPosition(8, 32); interactableChoose->setDefaultText("Dialogue"); propChoose = tgui::ComboBox::create(); @@ -61,6 +63,16 @@ RoomLayerViewVisitor::~RoomLayerViewVisitor() { } } +void RoomLayerViewVisitor::updateInteractableChoose() { + interactableChoose->onItemSelect.disconnectAll(); + interactableChoose->removeAllItems(); + auto map = Editor::instance->getProject()->getInteractableNames(); + for (auto &[key, val] : map) { + interactableChoose->addItem(val, key.c_str()); + } + interactableChoose->setSelectedItemByIndex(0); +} + void RoomLayerViewVisitor::operator()(enum_v) { isAvailable = true; group->add(tileSetView); @@ -73,15 +85,9 @@ void RoomLayerViewVisitor::operator()(enum_v) { void RoomLayerViewVisitor::operator()(enum_v) { isAvailable = true; + updateInteractableChoose(); if (tool == RoomTool::TOOL_PLACE) { - interactableChoose->removeAllItems(); - auto map = Editor::instance->getProject()->getInteractableNames(); - for (auto &[key, val] : map) { - interactableChoose->addItem(val, key.c_str()); - } - interactableChoose->setSelectedItemByIndex(0); - group->add(tgui::Label::create("Interactables")); group->add(interactableChoose); @@ -89,6 +95,31 @@ void RoomLayerViewVisitor::operator()(enum_v) { if (inter == nullptr) { group->add(tgui::Label::create("Interactables")); } else { + auto interactableNames = Editor::instance->getProject()->getInteractableNames(); + std::unique_ptr typeInter; + for (auto &[key, val] : interactableNames) { + if (std::string(GetFileNameWithoutExt(key.c_str())) == inter->getType()) { + typeInter = std::make_unique(key); + + // Add missing props. + for (auto item : typeInter->getProps().items()) { + if (!inter->getProps().contains(item.key())) { + inter->getProps().push_back({item.key(), item.value()}); + } + } + + // Remove non-existent props. + auto *ptr = inter->getPropsPtr(); + for (auto item : inter->getPropsPtr()->items()) { + if (!typeInter->getProps().contains(item.key())) { + inter->getProps().erase(item.key()); + } + } + + break; + } + } + auto onTouchCheck = tgui::CheckBox::create("Interact on touch?"); onTouchCheck->setSize(24, 24); onTouchCheck->setPosition(8, 8); @@ -109,6 +140,7 @@ void RoomLayerViewVisitor::operator()(enum_v) { void RoomLayerViewVisitor::operator()(enum_v) { isAvailable = true; + updateInteractableChoose(); if (tool == RoomTool::TOOL_PLACE) { group->add(tgui::Label::create("Props")); @@ -147,13 +179,17 @@ void RoomLayerViewVisitor::operator()(enum_v) { } void RoomLayerViewVisitor::operator()(enum_v) { + updateInteractableChoose(); + if (tool == RoomTool::TOOL_PLACE) { + auto vec = Editor::instance->getProject()->getPaths(EngineFileType::FILE_ACTOR); + if (vec.size() == 0) return; + group->add(tgui::Label::create("Actors")); group->add(actorNameInput); - actorChoose->removeAllItems(); - auto vec = Editor::instance->getProject()->getPaths(EngineFileType::FILE_ACTOR); + for (auto actorPath : vec) { actorChoose->addItem(GetFileNameWithoutExt(actorPath.c_str()), actorPath); } @@ -167,5 +203,68 @@ void RoomLayerViewVisitor::operator()(enum_v) { group->add(actorChoose); } else if (tool == RoomTool::TOOL_ERASE) { group->add(tgui::Label::create("Erase an Actor..")); + } else if (tool == RoomTool::TOOL_EDIT) { + if (actor == nullptr) { + group->add(tgui::Label::create("Actor does not exist at this position.")); + } else { + interactableChoose->setPosition(8, 64); + + interactableChoose->onItemSelect([this](const tgui::String &item) { + auto id = interactableChoose->getSelectedItemId(); + printf("%s: %s \n", item.toStdString().c_str(), id.toStdString().c_str()); + + actor->setInteractableFromPath(id.toStdString()); + }); + + group->add(tgui::Label::create(TextFormat("Editing \"%s\"", actorName.c_str()))); + + group->add(interactableChoose); + + interactableChoose->setDefaultText(""); + + auto hasInteractableCheck = tgui::CheckBox::create("Has Interactable?"); + hasInteractableCheck->setSize(16, 16); + hasInteractableCheck->setPosition(8, 32); + + auto propBox = PropertiesBox::create(); + propBox->setPosition(0, 84); + propBox->setSize("100%", "100% - 84"); + group->add(propBox); + + if (actor->hasInteractable()) { + auto intsMap = Editor::instance->getProject()->getInteractableNames(); + for (auto &[key, val] : intsMap) { + std::string lowerTypeName = TextToLower(val.c_str()); + if (lowerTypeName == actor->getInteractable()->getType()) { + interactableChoose->setSelectedItemById(key); + } + } + propBox->addPropsJson(actor->getInteractable()->getProps()); + interactableChoose->setVisible(true); + hasInteractableCheck->setChecked(true); + } else { + interactableChoose->setVisible(false); + hasInteractableCheck->setChecked(false); + } + + std::weak_ptr weakPropsBox = propBox; + hasInteractableCheck->onChange([this, weakPropsBox](bool value) { + interactableChoose->setVisible(value); + if (!weakPropsBox.expired()) { + weakPropsBox.lock()->setVisible(value); + } + if (value) { + interactableChoose->setSelectedItemByIndex(0); + actor->setInteractableFromPath(interactableChoose->getSelectedItemId().toStdString()); + if (!weakPropsBox.expired()) { + weakPropsBox.lock()->addPropsJson(actor->getInteractable()->getProps()); + } + } else { + actor->setHasInteractable(false); + } + }); + + group->add(hasInteractableCheck); + } } } diff --git a/src/editor/roomViewModesHandler.cpp b/src/editor/roomViewModesHandler.cpp index 81b2059c..c20e6f55 100644 --- a/src/editor/roomViewModesHandler.cpp +++ b/src/editor/roomViewModesHandler.cpp @@ -1,26 +1,26 @@ #include "roomViewModesHandler.hpp" + #include "raylib.h" RoomViewModesHandler::RoomViewModesHandler() {} void RoomViewModesHandler::handleMode(int x, int y) { - if (view.expired()) - return; + if (view.expired()) return; auto ptr = view.lock(); switch (ptr->tool) { - case RoomTool::TOOL_PLACE: - handlePlaceMode(x, y); - break; - case RoomTool::TOOL_ERASE: - handleEraseMode(x, y); - break; - case RoomTool::TOOL_EDIT: - handleEditMode(x, y); - break; - default: - break; + case RoomTool::TOOL_PLACE: + handlePlaceMode(x, y); + break; + case RoomTool::TOOL_ERASE: + handleEraseMode(x, y); + break; + case RoomTool::TOOL_EDIT: + handleEditMode(x, y); + break; + default: + break; } } @@ -37,18 +37,13 @@ void RoomViewModesHandler::handlePlaceMode(int x, int y) { if (CheckCollisionPointRec(state.mouseWorldPos, destRect)) { auto atlasTilePos = ptr->tileSetView->getSelectedTile(); - if (tileSet->areAtlasCoordsValid( - {static_cast(atlasTilePos.x), - static_cast(atlasTilePos.y)})) { - Rectangle atlasSourceRect = - ptr->getSourceRect(tileMap, atlasTilePos.x, atlasTilePos.y); + if (tileSet->areAtlasCoordsValid({static_cast(atlasTilePos.x), static_cast(atlasTilePos.y)})) { + Rectangle atlasSourceRect = ptr->getSourceRect(tileMap, atlasTilePos.x, atlasTilePos.y); IVector tileMouse = ptr->getTileAtMouse(); - Rectangle destRect = - ptr->getDestRect(tileMap, tileMouse.x, tileMouse.y); + Rectangle destRect = ptr->getDestRect(tileMap, tileMouse.x, tileMouse.y); - DrawTexturePro(texture, atlasSourceRect, destRect, {0.0f, 0.0f}, - 0.0f, Fade(WHITE, 0.7f)); + DrawTexturePro(texture, atlasSourceRect, destRect, {0.0f, 0.0f}, 0.0f, Fade(WHITE, 0.7f)); } } } @@ -81,23 +76,22 @@ void RoomViewModesHandler::handleEraseMode(int x, int y) { } void RoomViewModesHandler::handleModePress(tgui::Vector2f pos) { - if (view.expired()) - return; + if (view.expired()) return; auto ptr = view.lock(); switch (ptr->tool) { - case RoomTool::TOOL_PLACE: - handlePlacePress(pos); - break; - case RoomTool::TOOL_ERASE: - handleErasePress(pos); - break; - case RoomTool::TOOL_EDIT: - handleEditPress(pos); - break; - default: - break; + case RoomTool::TOOL_PLACE: + handlePlacePress(pos); + break; + case RoomTool::TOOL_ERASE: + handleErasePress(pos); + break; + case RoomTool::TOOL_EDIT: + handleEditPress(pos); + break; + default: + break; } } @@ -108,14 +102,11 @@ void RoomViewModesHandler::handlePlacePress(tgui::Vector2f pos) { IVector atlasTilePos = ptr->tileSetView->getSelectedTile(); if (tileMap->getTileSet()->areAtlasCoordsValid( - {static_cast(atlasTilePos.x), - static_cast(atlasTilePos.y)})) { + {static_cast(atlasTilePos.x), static_cast(atlasTilePos.y)})) { IVector tileMouse = ptr->getTileAtMouse(); - Vector2 worldPos = {static_cast(tileMouse.x), - static_cast(tileMouse.y)}; - Vector2 atlasPos = {static_cast(atlasTilePos.x), - static_cast(atlasTilePos.y)}; + Vector2 worldPos = {static_cast(tileMouse.x), static_cast(tileMouse.y)}; + Vector2 atlasPos = {static_cast(atlasTilePos.x), static_cast(atlasTilePos.y)}; tileMap->setTile(worldPos, atlasPos); } @@ -128,8 +119,7 @@ void RoomViewModesHandler::handleErasePress(tgui::Vector2f pos) { IVector tileMouse = ptr->getTileAtMouse(); - Vector2 worldPos = {static_cast(tileMouse.x), - static_cast(tileMouse.y)}; + Vector2 worldPos = {static_cast(tileMouse.x), static_cast(tileMouse.y)}; tileMap->setEmptyTile(worldPos); } @@ -140,22 +130,16 @@ void RoomViewModesHandler::handleEditPress(tgui::Vector2f pos) { TileMap *tileMap = ptr->room->getTileMap(); ptr->selectedTile = ptr->getTileAtMouse(); - Vector2 atlasCoords = - tileMap->getTile(ptr->selectedTile.x, ptr->selectedTile.y) - .getAtlasTile() - .getAtlasCoords(); - IVector atlasCoordsInt = {static_cast(atlasCoords.x), - static_cast(atlasCoords.y)}; + Vector2 atlasCoords = tileMap->getTile(ptr->selectedTile.x, ptr->selectedTile.y).getAtlasTile().getAtlasCoords(); + IVector atlasCoordsInt = {static_cast(atlasCoords.x), static_cast(atlasCoords.y)}; ptr->tileSetView->setSelectedTile(atlasCoordsInt); ptr->tileSetView->onTileSelected.disconnectAll(); ptr->tileSetView->onTileSelected([ptr, tileMap](IVector newTile) { IVector tileMouse = ptr->selectedTile; if (tileMouse.x >= 0) { - Vector2 worldPos = {static_cast(tileMouse.x), - static_cast(tileMouse.y)}; - Vector2 atlasPos = {static_cast(newTile.x), - static_cast(newTile.y)}; + Vector2 worldPos = {static_cast(tileMouse.x), static_cast(tileMouse.y)}; + Vector2 atlasPos = {static_cast(newTile.x), static_cast(newTile.y)}; tileMap->setTile(worldPos, atlasPos); } diff --git a/src/editor/saveables/fontWrapper.cpp b/src/editor/saveables/fontWrapper.cpp index 2919fe51..ecff51ea 100644 --- a/src/editor/saveables/fontWrapper.cpp +++ b/src/editor/saveables/fontWrapper.cpp @@ -1,7 +1,9 @@ #include "saveables/fontWrapper.hpp" -#include "raylib.h" + #include +#include "raylib.h" + FontWrapper::FontWrapper(const std::string &filePath) { font = LoadFont(filePath.c_str()); fontSource = filePath; diff --git a/src/editor/saveables/imageWrapper.cpp b/src/editor/saveables/imageWrapper.cpp index d5e9f5b3..409e52a6 100644 --- a/src/editor/saveables/imageWrapper.cpp +++ b/src/editor/saveables/imageWrapper.cpp @@ -1,8 +1,10 @@ #include "saveables/imageWrapper.hpp" -#include "raylib.h" + #include #include +#include "raylib.h" + ImageWrapper::ImageWrapper(const std::string &filePath) { printf("%s \n", filePath.c_str()); image = LoadImage(filePath.c_str()); diff --git a/src/editor/saveables/soundWrapper.cpp b/src/editor/saveables/soundWrapper.cpp index 78abc13c..d2470302 100644 --- a/src/editor/saveables/soundWrapper.cpp +++ b/src/editor/saveables/soundWrapper.cpp @@ -1,7 +1,9 @@ #include "saveables/soundWrapper.hpp" -#include "raylib.h" + #include +#include "raylib.h" + SoundWrapper::SoundWrapper(const std::string &filePath) { sound = LoadMusicStream(filePath.c_str()); source = filePath; diff --git a/src/editor/screens/projectScreen.cpp b/src/editor/screens/projectScreen.cpp index d6b2bdc2..d46084fa 100644 --- a/src/editor/screens/projectScreen.cpp +++ b/src/editor/screens/projectScreen.cpp @@ -1,4 +1,12 @@ #include "screens/projectScreen.hpp" + +#include +#include +#include +#include +#include +#include + #include "TGUI/Layout.hpp" #include "TGUI/String.hpp" #include "TGUI/Texture.hpp" @@ -6,6 +14,7 @@ #include "TGUI/Widgets/BitmapButton.hpp" #include "TGUI/Widgets/Button.hpp" #include "TGUI/Widgets/ComboBox.hpp" +#include "TGUI/Widgets/ContextMenu.hpp" #include "TGUI/Widgets/Group.hpp" #include "TGUI/Widgets/Label.hpp" #include "TGUI/Widgets/MenuBar.hpp" @@ -23,26 +32,17 @@ #include "services/fileSystemService.hpp" #include "services/translationService.hpp" #include "widgets/newFileDialog.hpp" -#include -#include -#include -#include -#include using namespace screens; -void ProjectScreen::layoutReload() { - resListWBinder->setSize(modifiable_RESLIST_W, "100%"); -} +void ProjectScreen::layoutReload() { resListWBinder->setSize(modifiable_RESLIST_W, "100%"); } void ProjectScreen::mouseMove(int x, int y) { - resourcesList->manualMouseMoved( - {static_cast(x), static_cast(y)}); + resourcesList->manualMouseMoved({static_cast(x), static_cast(y)}); fileTabs->manualMouseMoved( {static_cast( - x // coordinate of the mouse cursor relative to the projectScreen - - tabsContainer->getPosition().x // coordinate of the tabsContainer - // relative to the projectScreen - + tabsContainer->getContentOffset() - .x // coordinate of the widget relative to the tabsContainer + x // coordinate of the mouse cursor relative to the projectScreen + - tabsContainer->getPosition().x // coordinate of the tabsContainer + // relative to the projectScreen + + tabsContainer->getContentOffset().x // coordinate of the widget relative to the tabsContainer // why all of these calculations? cause the builtin // leftMousePressed method returns the mouse coordinate relative to // the current widget @@ -50,12 +50,10 @@ void ProjectScreen::mouseMove(int x, int y) { static_cast(y - tabsContainer->getPosition().y)}); } void ProjectScreen::leftMouseReleased(int x, int y) { - resourcesList->manualLeftMouseReleased( - {static_cast(x), static_cast(y)}); + resourcesList->manualLeftMouseReleased({static_cast(x), static_cast(y)}); fileTabs->manualLeftMouseReleased( {// ditto - static_cast(x - tabsContainer->getPosition().x + - tabsContainer->getContentOffset().x), + static_cast(x - tabsContainer->getPosition().x + tabsContainer->getContentOffset().x), static_cast(y - tabsContainer->getPosition().y)}); } @@ -75,12 +73,9 @@ void ProjectScreen::bindMenuBarAndHK(tgui::MenuBar::Ptr menuBarPtr) { auto redoAction = [this] { getCurrentFile().getView().redoAction(); }; - std::vector saveFileHierarchy = { - ts.getKey("menu.file._label"), ts.getKey("menu.file.save_file")}; - std::vector undoHierarchy = {ts.getKey("menu.edit._label"), - ts.getKey("menu.edit.undo")}; - std::vector redoHierarchy = {ts.getKey("menu.edit._label"), - ts.getKey("menu.edit.redo")}; + std::vector saveFileHierarchy = {ts.getKey("menu.file._label"), ts.getKey("menu.file.save_file")}; + std::vector undoHierarchy = {ts.getKey("menu.edit._label"), ts.getKey("menu.edit.undo")}; + std::vector redoHierarchy = {ts.getKey("menu.edit._label"), ts.getKey("menu.edit.redo")}; menuBarPtr->setMenuItemEnabled(saveFileHierarchy, true); menuBarPtr->connectMenuItem(saveFileHierarchy, saveAction); @@ -116,9 +111,15 @@ void ProjectScreen::initItems(tgui::Group::Ptr layout) { // together. auto _tab = tgui::Tabs::create(); + auto &ts = Editor::instance->getTranslations(); + fileContextMenu = tgui::ContextMenu::create(); - fileContextMenu->addMenuItem("Copy full path"); - fileContextMenu->addMenuItem("Delete."); + bindTranslationWithCallback(fileContextMenu, + [](std::shared_ptr menu, TranslationService &ts) { + menu->removeAllMenuItems(); + menu->addMenuItem(ts.getKey("context_menu.copy_full_path")); + menu->addMenuItem(ts.getKey("context_menu.delete")); + }); Editor::instance->getGui().gui->add(fileContextMenu); openedFiles = std::map>{}; @@ -144,14 +145,10 @@ void ProjectScreen::initItems(tgui::Group::Ptr layout) { tabsContainer->getRenderer()->setBorders({0, 0, 0, 0}); tabsContainer->getRenderer()->setRoundedBorderRadius(0); tabsContainer->getRenderer()->setPadding(0); - tabsContainer->setSize( - tgui::Layout("100%") - tgui::bindWidth(resListWBinder), FILETABS_H); - tabsContainer->setPosition(tgui::bindWidth(resListWBinder), - tgui::bindBottom(toolBar)); - tabsContainer->getVerticalScrollbar()->setPolicy( - tgui::Scrollbar::Policy::Never); - tabsContainer->getHorizontalScrollbar()->setPolicy( - tgui::Scrollbar::Policy::Never); + tabsContainer->setSize(tgui::Layout("100%") - tgui::bindWidth(resListWBinder), FILETABS_H); + tabsContainer->setPosition(tgui::bindWidth(resListWBinder), tgui::bindBottom(toolBar)); + tabsContainer->getVerticalScrollbar()->setPolicy(tgui::Scrollbar::Policy::Never); + tabsContainer->getHorizontalScrollbar()->setPolicy(tgui::Scrollbar::Policy::Never); fileTabs = FileTab::create(); fileTabs->setHeight(FILETABS_H); @@ -175,19 +172,16 @@ void ProjectScreen::initItems(tgui::Group::Ptr layout) { } }); - Editor::instance->getHotkeyService().registerHotkeyCallback( - "close_tab", [this] { fileTabs->closeCurrentTab(); }); + Editor::instance->getHotkeyService().registerHotkeyCallback("close_tab", [this] { fileTabs->closeCurrentTab(); }); tabsContainer->add(fileTabs); layout->add(tabsContainer); // File view - auto fileView = tgui::Group::create( - {tgui::Layout("100%") - tgui::bindWidth(resListWBinder), - tgui::Layout("100%") - tgui::bindHeight(toolBar) - - tgui::bindHeight(tabsContainer)}); - fileView->setPosition(tgui::bindWidth(resListWBinder), - tgui::bindBottom(tabsContainer)); + auto fileView = + tgui::Group::create({tgui::Layout("100%") - tgui::bindWidth(resListWBinder), + tgui::Layout("100%") - tgui::bindHeight(toolBar) - tgui::bindHeight(tabsContainer)}); + fileView->setPosition(tgui::bindWidth(resListWBinder), tgui::bindBottom(tabsContainer)); this->fileViewGroup = fileView; clearView(); layout->add(fileView); @@ -198,14 +192,10 @@ void ProjectScreen::initItems(tgui::Group::Ptr layout) { // FIXME: fix scaling issue on windows! } -void ProjectScreen::addFileView(EngineFileType fileType, - const std::string &path) { - - Editor::instance->getGui().gui->setTabKeyUsageEnabled( - fileType != EngineFileType::FILE_SCRIPT); +void ProjectScreen::addFileView(EngineFileType fileType, const std::string &path) { + Editor::instance->getGui().gui->setTabKeyUsageEnabled(fileType != EngineFileType::FILE_SCRIPT); - std::unique_ptr projectFile = - fileVisitor->visit(fileType, path); + std::unique_ptr projectFile = fileVisitor->visit(fileType, path); if (projectFile->isEmpty) { std::string mutPath = std::string(path); Editor::instance->getFs().openFileInDefaultApp(mutPath); @@ -237,8 +227,7 @@ void ProjectScreen::switchView(tgui::String id) { void ProjectScreen::clearView() { focusedFile = ""; fileViewGroup->removeAllWidgets(); - std::unique_ptr empty = - fileVisitor->visit(EngineFileType::FILE_EMPTY, "."); + std::unique_ptr empty = fileVisitor->visit(EngineFileType::FILE_EMPTY, "."); empty->initUi(fileViewGroup); empty->addWidgets(fileViewGroup); } @@ -261,15 +250,14 @@ tgui::Group::Ptr ProjectScreen::createToolBar() { assert(project && "project isn't instanciated (nullptr)"); - projectLabel->setText(project->getTitle()); + projectLabel->setText(project->getProgramSettings().projectTitle); toolBar->add(projectLabel, "projectLabel"); auto &fs = Editor::instance->getFs(); auto playBtnTooltip = Tooltip::create(""); - bindTranslation(playBtnTooltip, "screen.project.toolbar.play", - &Tooltip::setText); + bindTranslation(playBtnTooltip, "screen.project.toolbar.play", &Tooltip::setText); auto playBtn = tgui::BitmapButton::create(); auto playtestImg = tgui::Texture(fs.getResourcePath("playtest.png")); playBtn->setImage(playtestImg); @@ -280,8 +268,7 @@ tgui::Group::Ptr ProjectScreen::createToolBar() { toolBar->add(playBtn, "playBtn"); auto buildTooltip = Tooltip::create(""); - bindTranslation(buildTooltip, "screen.project.toolbar.build", - &Tooltip::setText); + bindTranslation(buildTooltip, "screen.project.toolbar.build", &Tooltip::setText); auto buildBtn = tgui::BitmapButton::create(); auto buildImg = tgui::Texture(fs.getResourcePath("build.png")); buildBtn->setImage(buildImg); @@ -291,59 +278,107 @@ tgui::Group::Ptr ProjectScreen::createToolBar() { buildBtn->setToolTip(buildTooltip); toolBar->add(buildBtn); + auto settingsBtn = tgui::BitmapButton::create(); + auto settingsImage = tgui::Texture(fs.getResourcePath("projectsettings.png")); + settingsBtn->setImage(settingsImage); + settingsBtn->setSize({barSize, "100%"}); + settingsBtn->setPosition({tgui::bindRight(buildBtn) + 8, 0}); + settingsBtn->onPress([] { Editor::instance->getGui().getChildWindowSubService()->openWindow("project_settings"); }); + toolBar->add(settingsBtn); + return toolBar; } void ProjectScreen::addResourceButtons(EngineFileType fileType) { + auto &ts = Editor::instance->getTranslations(); auto project = Editor::instance->getProject(); this->listedResourcesType = fileType; resourcesLayout->removeAllWidgets(); - resourcesLayout->getRenderer()->setSpaceBetweenWidgets( - RESLIST_ITEM_PADDING); + resourcesLayout->getRenderer()->setSpaceBetweenWidgets(RESLIST_ITEM_PADDING); for (auto filePath : project->getPaths(fileType)) { + std::string fileName = GetFileName(filePath.c_str()); + auto fileBtn = tgui::Button::create(GetFileName(filePath.c_str())); fileBtn->setSize("100%", RESLIST_RES_BTN_H); - fileBtn->onPress( - [this, fileType, filePath] { addFileView(fileType, filePath); }); - fileBtn->onRightMousePress([this, filePath] { + fileBtn->onPress([this, fileType, filePath] { addFileView(fileType, filePath); }); + fileBtn->onRightMousePress([this, filePath, project, fileName, &ts] { fileContextMenu->getMenuItems().at(0).text = filePath; - fileContextMenu->setPosition(GetMousePosition().x, - GetMousePosition().y); + fileContextMenu->setPosition(GetMousePosition().x, GetMousePosition().y); fileContextMenu->onMenuItemClick.disconnectAll(); fileContextMenu->onMenuItemClick( - [this, filePath](const std::vector &hierarchy) { - if (hierarchy[0] == "Copy full path") { + [this, filePath, project, fileName, &ts](const std::vector &hierarchy) { + if (hierarchy[0] == ts.getKey("context_menu.copy_full_path")) { SetClipboardText(filePath.c_str()); } - if (hierarchy[0] == "Delete.") { + if (hierarchy[0] == ts.getKey("context_menu.delete")) { + bool allowedDeletion = true; auto messageBox = tgui::MessageBox::create(); - messageBox->setText("Are you sure?"); - messageBox->addButton("Yes"); - messageBox->addButton("No"); - messageBox->setButtonAlignment( - tgui::HorizontalAlignment::Right); + + if (listedResourcesType == EngineFileType::FILE_MAP) { + auto defaultRoomPath = project->getGameSettings().defaultRoomPath; + if (defaultRoomPath.empty() && project->getPaths(EngineFileType::FILE_MAP).size() <= 1) { + bindTranslation(messageBox, "dialog.delete_file.room_must_exist", + &tgui::MessageBox::setText); + allowedDeletion = false; + } + + std::string checkedFilePath = TextFormat("maps/%s", fileName.c_str()); + if (defaultRoomPath == checkedFilePath) { + bindTranslation(messageBox, "dialog.delete_file.room_cannot_be_deleted", + &tgui::MessageBox::setText); + allowedDeletion = false; + } + } + + if (listedResourcesType == EngineFileType::FILE_ACTOR) { + auto playerActorPath = project->getGameSettings().playerActorPath; + + if (playerActorPath.empty() && fileName == "playerActor.ractor") { + bindTranslation(messageBox, "dialog.delete_file.player_actor_must_exist", + &tgui::MessageBox::setText); + allowedDeletion = false; + } + + std::string checkedFilePath = TextFormat("actors/%s", fileName.c_str()); + if (playerActorPath == checkedFilePath) { + bindTranslation(messageBox, "dialog.delete_file.player_actor_cannot_be_deleted", + &tgui::MessageBox::setText); + allowedDeletion = false; + } + } + + if (allowedDeletion) { + messageBox->setText("Are you sure?"); + bindTranslation(messageBox, "dialog.delete_file.title", &tgui::MessageBox::setText); + messageBox->addButton(ts.getKey("dialog.delete_file.yes")); + messageBox->addButton(ts.getKey("dialog.delete_file.no")); + } else { + messageBox->addButton(ts.getKey("dialog.delete_file.ok")); + } + EditorGuiService::centerWidget(messageBox); + messageBox->setButtonAlignment(tgui::HorizontalAlignment::Right); std::weak_ptr weakBox = messageBox; - messageBox->onButtonPress( - [this, weakBox, - filePath](const tgui::String &button) { - assert(button == "Yes" || button == "No"); - if (auto box = weakBox.lock()) { - if (button == "Yes") { - std::error_code ec; - std::filesystem::remove(filePath, ec); - addResourceButtons(listedResourcesType); - } - - if (auto parent = box->getParent()) - parent->remove(box); + messageBox->onButtonPress([this, weakBox, filePath, &ts](const tgui::String &button) { + assert(button == ts.getKey("dialog.delete_file.yes") || + button == ts.getKey("dialog.delete_file.no") || + button == ts.getKey("dialog.delete_file.ok")); + + if (auto box = weakBox.lock()) { + if (button == ts.getKey("dialog.delete_file.yes")) { + std::error_code ec; + std::filesystem::remove(filePath, ec); + addResourceButtons(listedResourcesType); } - }); + + if (auto parent = box->getParent()) parent->remove(box); + } + }); Editor::instance->getGui().gui->add(messageBox); } @@ -359,9 +394,7 @@ ResizableContainer::Ptr ProjectScreen::createResourcesList() { auto project = Editor::instance->getProject(); TranslationService &tService = Editor::instance->getTranslations(); - auto group = ResizableContainer::create( - {modifiable_RESLIST_W, tgui::Layout("100%") - TOOLBAR_H}, - {0, TOOLBAR_H}); + auto group = ResizableContainer::create({modifiable_RESLIST_W, tgui::Layout("100%") - TOOLBAR_H}, {0, TOOLBAR_H}); group->enableResize(ResizeDirection::RIGHT); group->setMinResizeWidth(MIN_RESLIST_W); group->setMaxResizeWidth(MAX_RESLIST_W); @@ -374,17 +407,20 @@ ResizableContainer::Ptr ProjectScreen::createResourcesList() { auto resourceChoose = tgui::ComboBox::create(); resourceChoose->setPosition(0, 0); resourceChoose->setSize("100%", RESLIST_RES_CHOOSE_H); + + int i = 0; for (auto typeName : Editor::instance->getFs().getTypeNames()) { - resourceChoose->addItem(typeName); + if (static_cast(i) != EngineFileType::FILE_EMPTY) { + resourceChoose->addItem(typeName); + } + i++; } // resourceChoose->addMultipleItems({"TileSets", "Maps", "Scripts"}); resourceChoose->setSelectedItem("Maps"); group->add(resourceChoose); auto createResourceBtn = tgui::Button::create(); - bindTranslation(createResourceBtn, - "screen.project.create_new_resource", - &tgui::Button::setText); + bindTranslation(createResourceBtn, "screen.project.create_new_resource", &tgui::Button::setText); createResourceBtn->setPosition(0, tgui::bindBottom(resourceChoose)); createResourceBtn->setSize("100%", RESLIST_CREATE_RES_BTN_H); createResourceBtn->onPress([this] { @@ -398,13 +434,10 @@ ResizableContainer::Ptr ProjectScreen::createResourcesList() { group->add(createResourceBtn); auto resourceListPanel = tgui::ScrollablePanel::create( - {"100%", tgui::Layout("100%") - - (RESLIST_RES_CHOOSE_H + RESLIST_CREATE_RES_BTN_H)}); + {"100%", tgui::Layout("100%") - (RESLIST_RES_CHOOSE_H + RESLIST_CREATE_RES_BTN_H)}); resourceListPanel->setPosition(0, tgui::bindBottom(createResourceBtn)); - resourceListPanel->getVerticalScrollbar()->setPolicy( - tgui::Scrollbar::Policy::Automatic); - resourceListPanel->getHorizontalScrollbar()->setPolicy( - tgui::Scrollbar::Policy::Never); + resourceListPanel->getVerticalScrollbar()->setPolicy(tgui::Scrollbar::Policy::Automatic); + resourceListPanel->getHorizontalScrollbar()->setPolicy(tgui::Scrollbar::Policy::Never); resourcesLayout = tgui::GrowVerticalLayout::create(); resourceListPanel->add(resourcesLayout); @@ -416,8 +449,7 @@ ResizableContainer::Ptr ProjectScreen::createResourcesList() { }); if (project != nullptr) { - EngineFileType currentFileType = - static_cast(resourceChoose->getSelectedItemIndex()); + EngineFileType currentFileType = static_cast(resourceChoose->getSelectedItemIndex()); addResourceButtons(currentFileType); } diff --git a/src/editor/screens/welcomeScreen.cpp b/src/editor/screens/welcomeScreen.cpp index 7daeb64c..790a3951 100644 --- a/src/editor/screens/welcomeScreen.cpp +++ b/src/editor/screens/welcomeScreen.cpp @@ -1,4 +1,7 @@ #include "screens/welcomeScreen.hpp" + +#include + #include "TGUI/Layout.hpp" #include "TGUI/String.hpp" #include "TGUI/Widgets/BoxLayout.hpp" @@ -16,22 +19,15 @@ #include "services/editorGuiService.hpp" #include "services/translationService.hpp" #include "widgets/newProjectWindow.hpp" -#include void screens::WelcomeScreen::initItems(tgui::Group::Ptr layout) { auto &ts = Editor::instance->getTranslations(); if (!Editor::instance->getGui().menuBar.expired()) { auto menuBarPtr = Editor::instance->getGui().menuBar.lock(); - menuBarPtr->setMenuItemEnabled( - {ts.getKey("menu.file._label"), ts.getKey("menu.file.save_file")}, - false); - menuBarPtr->setMenuItemEnabled( - {ts.getKey("menu.edit._label"), ts.getKey("menu.edit.undo")}, - false); - menuBarPtr->setMenuItemEnabled( - {ts.getKey("menu.edit._label"), ts.getKey("menu.edit.redo")}, - false); + menuBarPtr->setMenuItemEnabled({ts.getKey("menu.file._label"), ts.getKey("menu.file.save_file")}, false); + menuBarPtr->setMenuItemEnabled({ts.getKey("menu.edit._label"), ts.getKey("menu.edit.undo")}, false); + menuBarPtr->setMenuItemEnabled({ts.getKey("menu.edit._label"), ts.getKey("menu.edit.redo")}, false); } const auto verticalLayout = tgui::GrowVerticalLayout::create(); @@ -43,15 +39,13 @@ void screens::WelcomeScreen::initItems(tgui::Group::Ptr layout) { EditorGuiService::createLogoCenter(verticalLayout); const auto headerLabel = tgui::Label::create(""); - bindTranslation(headerLabel, "screen.starting.get_started", - &tgui::Label::setText); + bindTranslation(headerLabel, "screen.starting.get_started", &tgui::Label::setText); headerLabel->setTextSize(32); headerLabel->setHorizontalAlignment(tgui::HorizontalAlignment::Center); verticalLayout->add(headerLabel); const auto introLabel = tgui::Label::create(""); - bindTranslation(introLabel, "screen.starting.description", - &tgui::Label::setText); + bindTranslation(introLabel, "screen.starting.description", &tgui::Label::setText); introLabel->setTextSize(16); introLabel->setHorizontalAlignment(tgui::HorizontalAlignment::Center); verticalLayout->add(introLabel); @@ -68,27 +62,22 @@ void screens::WelcomeScreen::initItems(tgui::Group::Ptr layout) { const auto actionsLabel = tgui::Label::create(""); actionsLabel->setTextSize(24); left->add(actionsLabel); - bindTranslation(actionsLabel, "screen.starting.actions", - &tgui::Label::setText); + bindTranslation(actionsLabel, "screen.starting.actions", &tgui::Label::setText); const auto newProjButton = tgui::Button::create(); - bindTranslation(newProjButton, "menu.file.new_project", - &tgui::Button::setText); + bindTranslation(newProjButton, "menu.file.new_project", &tgui::Button::setText); newProjButton->setTextSize(ACTION_BUTTON_SIZE); const auto buttonPadding = tgui::BoxLayout::create(); buttonPadding->setHeight(10); const auto openProjButton = tgui::Button::create(); - bindTranslation(openProjButton, "menu.file.open_project", - &tgui::Button::setText); + bindTranslation(openProjButton, "menu.file.open_project", &tgui::Button::setText); openProjButton->setTextSize(ACTION_BUTTON_SIZE); - newProjButton->onPress( - [this] { Editor::instance->getFs().promptNewProject(); }); + newProjButton->onPress([this] { Editor::instance->getFs().promptNewProject(); }); - openProjButton->onPress( - [] { Editor::instance->getFs().promptOpenProject(); }); + openProjButton->onPress([] { Editor::instance->getFs().promptOpenProject(); }); left->add(newProjButton); left->add(buttonPadding); @@ -103,9 +92,7 @@ void screens::WelcomeScreen::initItems(tgui::Group::Ptr layout) { right->setAutoLayout(tgui::AutoLayout::Fill); const auto recentProjectLabel = tgui::Label::create(""); - bindTranslation(recentProjectLabel, - "screen.starting.recent_projects", - &tgui::Label::setText); + bindTranslation(recentProjectLabel, "screen.starting.recent_projects", &tgui::Label::setText); recentProjectLabel->setTextSize(24); recentProjectLabel->setAutoLayout(tgui::AutoLayout::Top); right->add(recentProjectLabel); @@ -113,13 +100,11 @@ void screens::WelcomeScreen::initItems(tgui::Group::Ptr layout) { const auto recentProject = tgui::ListBox::create(); recentProject->setAutoLayout(tgui::AutoLayout::Fill); - for (auto i : - Editor::instance->getRecentProjectService().getRecentProjects()) { + for (auto i : Editor::instance->getRecentProjectService().getRecentProjects()) { recentProject->addItem(i); } - recentProject->onItemSelect( - [this](const tgui::String &path) { Project::openProject(path); }); + recentProject->onItemSelect([this](const tgui::String &path) { Project::openProject(path); }); right->add(recentProject); diff --git a/src/editor/services/childWindowSubService.cpp b/src/editor/services/childWindowSubService.cpp index 62781fb0..29f12ef8 100644 --- a/src/editor/services/childWindowSubService.cpp +++ b/src/editor/services/childWindowSubService.cpp @@ -1,28 +1,55 @@ #include "services/childWindowSubService.hpp" + +#include + #include "childWindows/aboutWindow.hpp" +#include "childWindows/addDelayDialogueWindow.hpp" +#include "childWindows/addDialogueOptionWindow.hpp" +#include "childWindows/colorSelectWindow.hpp" +#include "childWindows/editDialogueOptionWindow.hpp" +#include "childWindows/editPropWindow.hpp" +#include "childWindows/newPropWindow.hpp" #include "childWindows/popupWindow.hpp" +#include "childWindows/projectSettingsWindow.hpp" #include "childWindows/settingsWindow.hpp" -#include ChildWindowSubService::ChildWindowSubService() { this->createWindows(); } void ChildWindowSubService::createWindows() { - if (!this->childWindows.empty()) - this->childWindows.clear(); + if (!this->childWindows.empty()) this->childWindows.clear(); + + this->childWindows.try_emplace("about", std::make_unique()); + + this->childWindows.try_emplace("options", std::make_unique()); + + this->childWindows.try_emplace("project_settings", std::make_unique()); - this->childWindows.try_emplace( - "about", std::unique_ptr(new AboutWindow())); + this->childWindows.try_emplace("new_prop", std::make_unique()); - this->childWindows.try_emplace( - "options", std::unique_ptr(new SettingsWindow())); + this->childWindows.try_emplace("edit_prop", std::make_unique()); + + this->childWindows.try_emplace("select_a_color", std::make_unique()); + + this->childWindows.try_emplace("add_a_delay", std::make_unique()); + + this->childWindows.try_emplace("add_dialogue_option", std::make_unique()); + + this->childWindows.try_emplace("edit_dialogue_option", std::make_unique()); } void ChildWindowSubService::openWindow(const std::string &windowName) { - if (this->childWindows.count(windowName) == 1) - this->childWindows[windowName]->open(); + if (this->childWindows.count(windowName) == 1) this->childWindows[windowName]->open(); } void ChildWindowSubService::resetAndOpen(const std::string windowName) { this->createWindows(); this->openWindow(windowName); } + +PopupWindow *ChildWindowSubService::getWindow(const std::string &windowName) { + if (this->childWindows.count(windowName) == 1) { + return this->childWindows[windowName].get(); + } else { + return nullptr; + } +} diff --git a/src/editor/services/configurationService.cpp b/src/editor/services/configurationService.cpp index 4814e781..481355c0 100644 --- a/src/editor/services/configurationService.cpp +++ b/src/editor/services/configurationService.cpp @@ -1,12 +1,14 @@ #include "services/configurationService.hpp" -#include "defaultConfig.hpp" -#include "ini.h" -#include "raylib.h" + #include #include #include #include +#include "defaultConfig.hpp" +#include "ini.h" +#include "raylib.h" + void ConfigurationService::regenerate() { assert(this->iniFile && "iniFile is not initialized"); for (auto &[field, kv] : BASE_CONFIG) { @@ -14,8 +16,7 @@ void ConfigurationService::regenerate() { if (!this->iniStructure.has(field)) { this->iniStructure.set(field, mINI::INIMap()); } - if (this->iniStructure[field].has(k)) - continue; + if (this->iniStructure[field].has(k)) continue; this->iniStructure[field].set(k, v); } } @@ -35,13 +36,11 @@ ConfigurationService::ConfigurationService() { this->regenerate(); }; -mINI::INIMap> -ConfigurationService::getField(const std::string &field) { +mINI::INIMap> ConfigurationService::getField(const std::string &field) { return this->iniStructure[field]; } -std::string ConfigurationService::getStringValue(const std::string &field, - const std::string &key) { +std::string ConfigurationService::getStringValue(const std::string &field, const std::string &key) { return this->iniStructure[field][key]; } @@ -49,16 +48,11 @@ std::string ConfigurationService::getStringValue(const std::string &key) { return this->getStringValue(GENERAL_CONF_FIELD, key); } -void ConfigurationService::setStringValue(const std::string &field, - const std::string &key, - const std::string &value) { +void ConfigurationService::setStringValue(const std::string &field, const std::string &key, const std::string &value) { this->iniStructure[field].set(key, value); } -void ConfigurationService::setStringValue(const std::string &key, - const std::string &value) { +void ConfigurationService::setStringValue(const std::string &key, const std::string &value) { this->setStringValue(GENERAL_CONF_FIELD, key, value); } -void ConfigurationService::saveConfiguration() { - this->iniFile->write(this->iniStructure); -} +void ConfigurationService::saveConfiguration() { this->iniFile->write(this->iniStructure); } diff --git a/src/editor/services/editorGuiService.cpp b/src/editor/services/editorGuiService.cpp index f591cf8f..3298ca9d 100644 --- a/src/editor/services/editorGuiService.cpp +++ b/src/editor/services/editorGuiService.cpp @@ -1,4 +1,12 @@ #include "services/editorGuiService.hpp" + +#include +#include +#include +#include +#include +#include + #include "TGUI/Backend/raylib.hpp" #include "TGUI/Loading/Theme.hpp" #include "TGUI/ObjectConverter.hpp" @@ -13,12 +21,6 @@ #include "services/childWindowSubService.hpp" #include "services/translationService.hpp" #include "updatable.hpp" -#include -#include -#include -#include -#include -#include constexpr int BASE_WINDOW_WIDTH = 800; constexpr int BASE_WINDOW_HEIGHT = 600; @@ -45,12 +47,9 @@ void EditorGuiService::init() { hks.deserialize(cfgs.getField("hotkeys")); this->resetUi(); - hks.registerHotkeyCallback("toggle_debug", - [this]() { perfOverlay.Toggle(); }); - hks.registerHotkeyCallback( - "new_project", [] { Editor::instance->getFs().promptNewProject(); }); - hks.registerHotkeyCallback( - "open_project", [] { Editor::instance->getFs().promptOpenProject(); }); + hks.registerHotkeyCallback("toggle_debug", [this]() { perfOverlay.Toggle(); }); + hks.registerHotkeyCallback("new_project", [] { Editor::instance->getFs().promptNewProject(); }); + hks.registerHotkeyCallback("open_project", [] { Editor::instance->getFs().promptOpenProject(); }); } void EditorGuiService::resetUi() { @@ -97,8 +96,7 @@ void EditorGuiService::uiLoop() { auto const &cg = this->gui; SetTraceLogLevel(LOG_WARNING); - tgui::Theme::addRendererInheritanceParent("NewProjectWindow", - "ChildWindow"); + tgui::Theme::addRendererInheritanceParent("NewProjectWindow", "ChildWindow"); tgui::Theme::addRendererInheritanceParent("RoomToolbox", "Tabs"); // main loop. while (!WindowShouldClose()) { @@ -128,8 +126,7 @@ void EditorGuiService::uiLoop() { leftMouseHeld = true; } else { if (leftMouseHeld) { - currentScreen->leftMouseReleased(GetMouseX(), - GetMouseY() - MENUBAR_H); + currentScreen->leftMouseReleased(GetMouseX(), GetMouseY() - MENUBAR_H); leftMouseHeld = false; } } @@ -137,19 +134,15 @@ void EditorGuiService::uiLoop() { BeginDrawing(); ClearBackground(DARKGRAY); - auto bgProp = tgui::Theme::getDefault()->getGlobalProperty( - "BackgroundColorDisabled"); + auto bgProp = tgui::Theme::getDefault()->getGlobalProperty("BackgroundColorDisabled"); if (bgProp.getType() == tgui::ObjectConverter::Type::None) { - bgProp = - tgui::Theme::getDefault()->getGlobalProperty("BackgroundColor"); + bgProp = tgui::Theme::getDefault()->getGlobalProperty("BackgroundColor"); } auto bgColor = bgProp.getColor(); - auto topGradientColor = static_cast( - abs(sin(GetTime() * GRADIENT_SPEED_MUTLIPLIER)) * - GRADIENT_COLOR_MULTIPLIER); - DrawRectangle( - 0, 0, GetRenderWidth(), GetRenderHeight(), - {bgColor.getRed(), bgColor.getGreen(), bgColor.getBlue(), 255}); + auto topGradientColor = + static_cast(abs(sin(GetTime() * GRADIENT_SPEED_MUTLIPLIER)) * GRADIENT_COLOR_MULTIPLIER); + DrawRectangle(0, 0, GetRenderWidth(), GetRenderHeight(), + {bgColor.getRed(), bgColor.getGreen(), bgColor.getBlue(), 255}); cg->draw(); // Due to many reasons, one time... Thefirey33 decided to talk // to the C++ MSVC Compiler if he can reset the current state of @@ -171,11 +164,8 @@ void EditorGuiService::uiLoop() { gui.reset(); } -void EditorGuiService::setScreen(std::unique_ptr setToScreen, - bool forceSwitch) { - if (this->currentScreen != nullptr && - setToScreen->getNameOfScreen() == - this->currentScreen->getNameOfScreen() && +void EditorGuiService::setScreen(std::unique_ptr setToScreen, bool forceSwitch) { + if (this->currentScreen != nullptr && setToScreen->getNameOfScreen() == this->currentScreen->getNameOfScreen() && !forceSwitch) { return; } @@ -198,22 +188,17 @@ tgui::Group::Ptr EditorGuiService::uiChangePreInit(UIScreen *setToScreen) { screenContainer.lock()->removeAllWidgets(); - if (this->currentScreen != nullptr) - this->currentScreen->unloadScreen(); + if (this->currentScreen != nullptr) this->currentScreen->unloadScreen(); std::string title = "RPG++ Editor - "; title.append(setToScreen->getNameOfScreen()); SetWindowTitle(title.c_str()); return screenContainer.lock(); } -void EditorGuiService::addUpdate(std::shared_ptr widget) { - updatableWidgets.push_back(widget); -} +void EditorGuiService::addUpdate(std::shared_ptr widget) { updatableWidgets.push_back(widget); } void EditorGuiService::setScreen(UIScreen *setToScreen, bool forceSwitch) { - if (this->currentScreen != nullptr && - setToScreen->getNameOfScreen() == - this->currentScreen->getNameOfScreen() && + if (this->currentScreen != nullptr && setToScreen->getNameOfScreen() == this->currentScreen->getNameOfScreen() && !forceSwitch) { return; } @@ -224,12 +209,9 @@ void EditorGuiService::setScreen(UIScreen *setToScreen, bool forceSwitch) { gui->add(group); } -void EditorGuiService::createLogoCenter( - const tgui::GrowVerticalLayout::Ptr &layout) { - +void EditorGuiService::createLogoCenter(const tgui::GrowVerticalLayout::Ptr &layout) { const auto boxLayout = tgui::BoxLayout::create({"100%", 96}); - std::string logoPath = - Editor::instance->getFs().getResourcePath("logo-ups.png"); + std::string logoPath = Editor::instance->getFs().getResourcePath("logo-ups.png"); const auto welcomePic = tgui::Picture::create(logoPath.c_str()); welcomePic->setOrigin({0.5, 0.5}); welcomePic->setPosition({"50%", "50%"}); @@ -247,9 +229,7 @@ void EditorGuiService::reloadUi() { */ } -ChildWindowSubService *EditorGuiService::getChildWindowSubService() { - return this->childWindowService.get(); -} +ChildWindowSubService *EditorGuiService::getChildWindowSubService() { return this->childWindowService.get(); } void EditorGuiService::initMenuBar() { auto menuBarPtr = tgui::MenuBar::create(); @@ -262,14 +242,10 @@ void EditorGuiService::initMenuBar() { menuBarPtr->addMenu(fileT); menuBarPtr->addMenuItem(fileNewProjectT); - menuBarPtr->connectMenuItem({fileT, fileNewProjectT}, [] { - Editor::instance->getFs().promptNewProject(); - }); + menuBarPtr->connectMenuItem({fileT, fileNewProjectT}, [] { Editor::instance->getFs().promptNewProject(); }); menuBarPtr->addMenuItem(fileOpenProjectT); menuBarPtr->addMenuItem(ts.getKey("menu.file.save_file")); - menuBarPtr->connectMenuItem({fileT, fileOpenProjectT}, [] { - Editor::instance->getFs().promptOpenProject(); - }); + menuBarPtr->connectMenuItem({fileT, fileOpenProjectT}, [] { Editor::instance->getFs().promptOpenProject(); }); menuBarPtr->addMenu(ts.getKey("menu.edit._label")); menuBarPtr->addMenuItem(ts.getKey("menu.edit.undo")); @@ -279,26 +255,21 @@ void EditorGuiService::initMenuBar() { const auto editorOptionsTranslation = ts.getKey("menu.options.editor"); menuBarPtr->addMenu(optionsTranslation); menuBarPtr->addMenuItem(editorOptionsTranslation); - menuBarPtr->connectMenuItem( - {optionsTranslation, editorOptionsTranslation}, - [&] { this->childWindowService->openWindow("options"); }); + menuBarPtr->connectMenuItem({optionsTranslation, editorOptionsTranslation}, + [&] { this->childWindowService->openWindow("options"); }); - const auto &aboutOptions = ts.getKey("menu.about._label"), - &aboutRpgpp = ts.getKey("menu.about.rpgpp"); + const auto &aboutOptions = ts.getKey("menu.about._label"), &aboutRpgpp = ts.getKey("menu.about.rpgpp"); menuBarPtr->addMenu(aboutOptions); menuBarPtr->addMenuItem(aboutRpgpp); - menuBarPtr->connectMenuItem({aboutOptions, aboutRpgpp}, [&] { - this->childWindowService->openWindow("about"); - }); + menuBarPtr->connectMenuItem({aboutOptions, aboutRpgpp}, [&] { this->childWindowService->openWindow("about"); }); menuBarPtr->setSize({"100%", MENUBAR_H}); this->gui->add(menuBarPtr); } void EditorGuiService::gotoPreviousScreen() { if (!this->screenHistory.empty()) { - std::unique_ptr lastScreen = - std::move(this->screenHistory.back()); + std::unique_ptr lastScreen = std::move(this->screenHistory.back()); this->screenHistory.pop_back(); auto group = this->uiChangePreInit(lastScreen.get()); @@ -309,9 +280,8 @@ void EditorGuiService::gotoPreviousScreen() { } void EditorGuiService::centerWidget(tgui::Widget::Ptr widget) { - widget->setPosition( - (GetScreenWidth() / 2.0f) - (widget->getSize().x / 2.0f), - (GetScreenHeight() / 2.0f) - (widget->getSize().y / 2.0f)); + widget->setPosition((GetScreenWidth() / 2.0f) - (widget->getSize().x / 2.0f), + (GetScreenHeight() / 2.0f) - (widget->getSize().y / 2.0f)); } void EditorGuiService::alert(tgui::String title, tgui::String content) { diff --git a/src/editor/services/fileSystemService.cpp b/src/editor/services/fileSystemService.cpp index 73d14a13..5199533e 100644 --- a/src/editor/services/fileSystemService.cpp +++ b/src/editor/services/fileSystemService.cpp @@ -1,10 +1,12 @@ #include "services/fileSystemService.hpp" -#include "TGUI/Widgets/FileDialog.hpp" -#include "widgets/newProjectWindow.hpp" + #include #include #include +#include "TGUI/Widgets/FileDialog.hpp" +#include "widgets/newProjectWindow.hpp" + #ifdef __linux__ #include #endif @@ -19,6 +21,7 @@ FileSystemService::FileSystemService() { editorBaseDir = GetWorkingDirectory(); + /// type names typeNames[static_cast(EngineFileType::FILE_TILESET)] = "Tilesets"; typeNames[static_cast(EngineFileType::FILE_MAP)] = "Maps"; typeNames[static_cast(EngineFileType::FILE_ACTOR)] = "Actors"; @@ -29,12 +32,25 @@ FileSystemService::FileSystemService() { typeNames[static_cast(EngineFileType::FILE_MUSIC)] = "Music"; typeNames[static_cast(EngineFileType::FILE_PROP)] = "Props"; typeNames[static_cast(EngineFileType::FILE_SCRIPT)] = "Scripts"; - - typeNames[static_cast(EngineFileType::FILE_EMPTY)] = - "Project Directory"; + typeNames[static_cast(EngineFileType::FILE_INTERACTABLE)] = "Interactables"; + + typeNames[static_cast(EngineFileType::FILE_EMPTY)] = "Project Directory"; + + /// type extensions + typeExtensions[static_cast(EngineFileType::FILE_TILESET)] = {".rtiles"}; + typeExtensions[static_cast(EngineFileType::FILE_MAP)] = {".rmap"}; + typeExtensions[static_cast(EngineFileType::FILE_ACTOR)] = {".ractor"}; + typeExtensions[static_cast(EngineFileType::FILE_DIALOGUE)] = {".rdiag"}; + typeExtensions[static_cast(EngineFileType::FILE_IMAGE)] = {".png", ".jpg"}; + typeExtensions[static_cast(EngineFileType::FILE_FONT)] = {".ttf"}; + typeExtensions[static_cast(EngineFileType::FILE_SOUND)] = {".wav", ".mp3"}; + typeExtensions[static_cast(EngineFileType::FILE_MUSIC)] = {".wav", ".mp3"}; + typeExtensions[static_cast(EngineFileType::FILE_PROP)] = {".rprop"}; + typeExtensions[static_cast(EngineFileType::FILE_SCRIPT)] = {".lua"}; + typeExtensions[static_cast(EngineFileType::FILE_INTERACTABLE)] = {".rinter"}; } -void FileSystemService::unload() { } +void FileSystemService::unload() {} void FileSystemService::promptNewProject() { auto newProjectDialog = NewProjectWindow::create(); @@ -42,10 +58,15 @@ void FileSystemService::promptNewProject() { newProjectDialog->init(Editor::instance->getGui().gui.get()); newProjectDialog->fileField->setSelectingDirectory(true); newProjectDialog->confirmButton->onPress([newProjectDialog] { - std::string title = - newProjectDialog->titleField->getText().toStdString(); - std::string dirPath = - newProjectDialog->fileField->getChosenPath().toStdString(); + std::string title = newProjectDialog->titleField->getText().toStdString(); + std::string dirPath = newProjectDialog->fileField->getChosenPath().toStdString(); + + if (newProjectDialog->makeDirCheck->isChecked()) { + std::string newDirPath = TextFormat("%s/%s", dirPath.c_str(), title.c_str()); + MakeDirectory(newDirPath.c_str()); + dirPath = newDirPath; + } + if (!title.empty() && !dirPath.empty()) { auto path = Project::create(dirPath, title); Project::openProject(path, true); @@ -58,24 +79,23 @@ void FileSystemService::promptOpenProject() { auto files = tgui::FileDialog::create(); files->setFileTypeFilters({{"RPG++ Project", {"*.rpgpp"}}}); - files->onFileSelect( - [](const tgui::String &filePath) { Project::openProject(filePath); }); + files->onFileSelect([](const tgui::String &filePath) { Project::openProject(filePath); }); Editor::instance->getGui().gui->add(files); } -std::string &FileSystemService::getTypeName(EngineFileType fileType) { - return typeNames[static_cast(fileType)]; -} +std::string &FileSystemService::getTypeName(EngineFileType fileType) { return typeNames[static_cast(fileType)]; } -std::array &FileSystemService::getTypeNames() { - return typeNames; -} +std::array &FileSystemService::getTypeNames() { return typeNames; } -const std::string &FileSystemService::getEditorBaseDir() { - return editorBaseDir; +std::vector &FileSystemService::getTypeExtensions(EngineFileType fileType) { + return typeExtensions[static_cast(fileType)]; } +std::array, FILETYPE_MAX> &FileSystemService::getTypeExtensions() { return typeExtensions; } + +const std::string &FileSystemService::getEditorBaseDir() { return editorBaseDir; } + std::string FileSystemService::getResourcePath(const std::string &path) { std::filesystem::path result = editorBaseDir; result /= "resources"; diff --git a/src/editor/services/hotkeyService.cpp b/src/editor/services/hotkeyService.cpp index ff6c4a9c..99e8b198 100644 --- a/src/editor/services/hotkeyService.cpp +++ b/src/editor/services/hotkeyService.cpp @@ -1,8 +1,10 @@ #include "services/hotkeyService.hpp" -#include "raylib.h" + #include #include #include + +#include "raylib.h" HotkeyService::HotkeyService() {} // It's not true UUID, but it will work in this case @@ -18,8 +20,7 @@ std::string get_uuid() { std::string res; for (int i = 0; i < 16; i++) { - if (dash[i]) - res += "-"; + if (dash[i]) res += "-"; res += v[dist(rng)]; res += v[dist(rng)]; } @@ -37,9 +38,8 @@ const int HotkeyService::pack(Hotkey hk) { } const Hotkey HotkeyService::unpack(int packed) { - return Hotkey{(bool)((packed >> 0) & 1), (bool)((packed >> 1) & 1), - (bool)((packed >> 2) & 1), (bool)((packed >> 3) & 1), - static_cast(packed >> 4)}; + return Hotkey{(bool)((packed >> 0) & 1), (bool)((packed >> 1) & 1), (bool)((packed >> 2) & 1), + (bool)((packed >> 3) & 1), static_cast(packed >> 4)}; } std::map HotkeyService::serialize() { @@ -57,53 +57,40 @@ void HotkeyService::write(const std::string &keyId, const std::string &keyStr) { hotkeyMap[keyId] = unpack(k); } -void HotkeyService::deserialize( - const std::map &serialized) { +void HotkeyService::deserialize(const std::map &serialized) { hotkeyMap.clear(); for (auto &[keyId, keyStr] : serialized) { write(keyId, keyStr); } } -void HotkeyService::deserialize( - mINI::INIMap> iniSerialized) { +void HotkeyService::deserialize(mINI::INIMap> iniSerialized) { hotkeyMap.clear(); for (auto &[keyId, keyStr] : iniSerialized) { write(keyId, keyStr); } } -std::string HotkeyService::registerHotkeyCallback(const std::string &keyId, - std::function cb) { +std::string HotkeyService::registerHotkeyCallback(const std::string &keyId, std::function cb) { std::string uniqueHkCbId = get_uuid(); hotkeysCb[uniqueHkCbId] = {keyId, cb}; return uniqueHkCbId; } -void HotkeyService::unregisterHotkeyCallback(const std::string &uniqueHkCbId) { - hotkeysCb.erase(uniqueHkCbId); -} +void HotkeyService::unregisterHotkeyCallback(const std::string &uniqueHkCbId) { hotkeysCb.erase(uniqueHkCbId); } -void HotkeyService::addHotkey(const std::string &keyId, const Hotkey &keys) { - hotkeyMap[keyId] = keys; -} +void HotkeyService::addHotkey(const std::string &keyId, const Hotkey &keys) { hotkeyMap[keyId] = keys; } -void HotkeyService::removeHotkey(const std::string &keyId) { - hotkeyMap.erase(keyId); -} +void HotkeyService::removeHotkey(const std::string &keyId) { hotkeyMap.erase(keyId); } const HotkeyMap HotkeyService::listHotkeys() { return this->hotkeyMap; } void HotkeyService::fire() { for (auto &[keyId, keys] : hotkeyMap) { - if ((keys.ctrl ^ IsKeyDown(KEY_LEFT_CONTROL))) - continue; - if ((keys.shift ^ IsKeyDown(KEY_LEFT_SHIFT))) - continue; - if ((keys.alt ^ IsKeyDown(KEY_LEFT_ALT))) - continue; - if ((keys.super ^ IsKeyDown(KEY_LEFT_SUPER))) - continue; + if ((keys.ctrl ^ IsKeyDown(KEY_LEFT_CONTROL))) continue; + if ((keys.shift ^ IsKeyDown(KEY_LEFT_SHIFT))) continue; + if ((keys.alt ^ IsKeyDown(KEY_LEFT_ALT))) continue; + if ((keys.super ^ IsKeyDown(KEY_LEFT_SUPER))) continue; if (IsKeyDown(keys.key)) { for (auto [_, data] : hotkeysCb) { if (data.first == keyId) { diff --git a/src/editor/services/recentProjectService.cpp b/src/editor/services/recentProjectService.cpp index 2dd2f2e9..898f6420 100644 --- a/src/editor/services/recentProjectService.cpp +++ b/src/editor/services/recentProjectService.cpp @@ -1,10 +1,12 @@ #include "services/recentProjectService.hpp" -#include "raylib.h" + #include #include #include #include +#include "raylib.h" + RecentProjectService::RecentProjectService() { path = GetWorkingDirectory(); path /= RPGPP_RECENT_FILE; @@ -32,11 +34,9 @@ RecentProjectService::RecentProjectService() { } void RecentProjectService::save() { - std::ofstream file(path); if (!file.is_open()) { - std::cerr << "Failed to open recent project file for saving" - << std::endl; + std::cerr << "Failed to open recent project file for saving" << std::endl; return; } @@ -61,6 +61,4 @@ void RecentProjectService::enqueue(const std::string &projectPath) { save(); } -const std::deque &RecentProjectService::getRecentProjects() const { - return recentProjects; -} +const std::deque &RecentProjectService::getRecentProjects() const { return recentProjects; } diff --git a/src/editor/services/themeService.cpp b/src/editor/services/themeService.cpp index 30ee9431..61523d2e 100644 --- a/src/editor/services/themeService.cpp +++ b/src/editor/services/themeService.cpp @@ -1,18 +1,15 @@ -#include "TGUI/Loading/Theme.hpp" -#include "TGUI/Renderers/ButtonRenderer.hpp" -#include "editor.hpp" -#include "screens/projectScreen.hpp" -#include "services/fileSystemService.hpp" -#include #include #include #include + +#include "TGUI/Loading/Theme.hpp" +#include "editor.hpp" +#include "services/fileSystemService.hpp" using namespace std; namespace fs = std::filesystem; ThemeService::ThemeService(Editor *editor_ptr) { - for (const auto &theme : fs::directory_iterator( - editor_ptr->getFs().getResourcePath(THEME_DIR))) { + for (const auto &theme : fs::directory_iterator(editor_ptr->getFs().getResourcePath(THEME_DIR))) { // each theme is a folder, where the theme name is the folder name // itself in each folder should always have a file called "theme.txt" if (theme.is_directory()) { @@ -23,14 +20,12 @@ ThemeService::ThemeService(Editor *editor_ptr) { } } } - this->current_theme = - std::make_shared(this->themes[this->current_theme_name]); + this->current_theme = std::make_shared(this->themes[this->current_theme_name]); tgui::Theme::setDefault(this->current_theme); } void ThemeService::setTheme(const string &themeName) { if (this->themes.find(themeName) != this->themes.end()) { - this->current_theme_name = themeName; this->current_theme->load(this->themes[this->current_theme_name]); // this->current_theme = std::make_shared( diff --git a/src/editor/services/translationService.cpp b/src/editor/services/translationService.cpp index d9c34d18..235a6274 100644 --- a/src/editor/services/translationService.cpp +++ b/src/editor/services/translationService.cpp @@ -1,4 +1,5 @@ #include "services/translationService.hpp" + #include #include #include @@ -13,8 +14,7 @@ using json = nlohmann::json; -static void flattenJson(const json &j, - std::map> &out, +static void flattenJson(const json &j, std::map> &out, const std::string &prefix = "") { for (auto it = j.begin(); it != j.end(); ++it) { std::string key = prefix.empty() ? it.key() : prefix + "." + it.key(); @@ -29,31 +29,27 @@ static void flattenJson(const json &j, } void TranslationService::loadTranslation(const std::string &langKey) { - if (translations.find(langKey) != translations.end()) - return; + if (translations.find(langKey) != translations.end()) return; const auto directory_entry = translationFiles.at(langKey); ifstream file(directory_entry.path()); json parsed = json::parse(file); std::map> translated; flattenJson(parsed, translated); - this->translations.try_emplace(langKey, - std::move(translated)); + this->translations.try_emplace(langKey, std::move(translated)); } void TranslationService::unloadTranslation(const std::string &langKey) { - if (langKey == DEFAULT_LANGUAGE) - return; + if (langKey == DEFAULT_LANGUAGE) return; this->translations.erase(langKey); } TranslationService::TranslationService(Editor *editor_ptr) { auto languageInOptions = editor_ptr->getConfiguration().getStringValue("language"); - for (auto const &directory_entry : filesystem::directory_iterator( - editor_ptr->getFs().getResourcePath(TRANSLATION_FILE_LOCATION))) { + for (auto const &directory_entry : + filesystem::directory_iterator(editor_ptr->getFs().getResourcePath(TRANSLATION_FILE_LOCATION))) { // add the translation to the translations map. - if (directory_entry.path().extension() != ".json") - continue; + if (directory_entry.path().extension() != ".json") continue; const std::string langKey = directory_entry.path().stem().string(); auto [it, inserted] = translationFiles.try_emplace(langKey, directory_entry); @@ -67,12 +63,11 @@ TranslationService::TranslationService(Editor *editor_ptr) { } } if (translationFiles.find(languageInOptions) != translationFiles.end()) { - current_language = languageInOptions; - } else { - fprintf(stderr, "WARNING: language '%s' not found, falling back to default.\n", - languageInOptions.c_str()); - current_language = DEFAULT_LANGUAGE; - } + current_language = languageInOptions; + } else { + fprintf(stderr, "WARNING: language '%s' not found, falling back to default.\n", languageInOptions.c_str()); + current_language = DEFAULT_LANGUAGE; + } } void TranslationService::setLanguage(const std::string &language) { @@ -112,20 +107,18 @@ void TranslationService::purgeDeadListeners() { } } -// @notice Use of getKey is not recommended unless you guarantee that the widget -// using the provided translation can update itself when translation changes. -// Otherwise, please use `bindTranslation()` in `bindTranslation.hpp` +// @notice Use of getKey is not recommended outside of the `bindTranslationWithCallback()`'s callbacks +// unless you guarantee that the widget using `getKey()` can update itself when text translation changes. +// Otherwise, please use `bindTranslation()` or `bindTranslationWithCallback()` in `bindTranslation.hpp` TranslatedString TranslationService::getKey(const std::string &key) { if (translations.find(getCurrentLanguage()) != translations.end()) { - const auto& gotten_translations = translations[current_language]; + const auto &gotten_translations = translations[current_language]; if (gotten_translations.find(key) != gotten_translations.end()) { TranslatedString s = TranslatedString{gotten_translations.at(key)}; return s; } - TranslatedString s = - TranslatedString{translations[DEFAULT_LANGUAGE][key]}; - printf("TRANSLATION WARNING: %s key doesn't exist for language %s\n", - key.c_str(), current_language.c_str()); + TranslatedString s = TranslatedString{translations[DEFAULT_LANGUAGE][key]}; + printf("TRANSLATION WARNING: %s key doesn't exist for language %s\n", key.c_str(), current_language.c_str()); return s; } else { throw std::out_of_range("translation doesn't exist in translations."); @@ -135,10 +128,7 @@ TranslatedString TranslationService::getKey(const std::string &key) { // NOTE: the whole point of this function, is to retrieve the raw key of a // language file like "en_us", from the "language" key in the JSON. std::string TranslationService::getLanguageIdentifierByKey(const std::string &language_key) { - return std::find_if( - langKeyToName.begin(), langKeyToName.end(), - [&](std::pair entry) { - return entry.second == language_key; - }) + return std::find_if(langKeyToName.begin(), langKeyToName.end(), + [&](std::pair entry) { return entry.second == language_key; }) ->first; } diff --git a/src/editor/timeFormat.cpp b/src/editor/timeFormat.cpp index 76408c3f..77c3b85b 100644 --- a/src/editor/timeFormat.cpp +++ b/src/editor/timeFormat.cpp @@ -1,6 +1,8 @@ #include "timeFormat.hpp" -#include + #include + +#include #include std::string formatTime(float duration) { diff --git a/src/editor/views/actorView.cpp b/src/editor/views/actorView.cpp index ff0fd0ff..99516d15 100644 --- a/src/editor/views/actorView.cpp +++ b/src/editor/views/actorView.cpp @@ -1,4 +1,8 @@ #include "views/actorView.hpp" + +#include +#include + #include "TGUI/Vector2.hpp" #include "actor.hpp" #include "components/resizableCanvasBox.hpp" @@ -7,20 +11,15 @@ #include "raylib.h" #include "tileset.hpp" #include "views/worldView.hpp" -#include -#include constexpr float DELTATIME_DIFFERENCE = 100.0f; -ActorView::ActorView(ActorFileView *actorFileView) - : actorFileView(actorFileView) { +ActorView::ActorView(ActorFileView *actorFileView) : actorFileView(actorFileView) { camera.zoom = 5.0f; cameraMaxZoom = 10.0f; } -ActorView::Ptr ActorView::create(ActorFileView *actorFileView) { - return std::make_shared(actorFileView); -} +ActorView::Ptr ActorView::create(ActorFileView *actorFileView) { return std::make_shared(actorFileView); } ActorView::Ptr ActorView::create(ActorFileView *actorFileView, Actor *actor) { auto ptr = std::make_shared(actorFileView); @@ -31,23 +30,20 @@ ActorView::Ptr ActorView::create(ActorFileView *actorFileView, Actor *actor) { void ActorView::setActor(Actor *actor) { this->actor = actor; - this->collisionBox = std::make_unique( - "collisionRect", this->actor->getCollisionRect(), RED); + this->collisionBox = std::make_unique("collisionRect", this->actor->getCollisionRect(), RED); - this->atlasBox = std::make_unique( - "atlasRect", actor->getCurrentAnimationRectangle(), BLUE, false); + this->atlasBox = + std::make_unique("atlasRect", actor->getCurrentAnimationRectangle(), BLUE, false); actor->resetAnimation(); } void ActorView::mouseMoved(tgui::Vector2f pos) { - if (this->actor == nullptr) - return; + if (this->actor == nullptr) return; const auto &mousePos = getMouseWorldPos(); - collisionBox->mouseMoved(mousePos, RPGPP_DRAW_MULTIPLIER, - RPGPP_DRAW_MULTIPLIER); + collisionBox->mouseMoved(mousePos, RPGPP_DRAW_MULTIPLIER, RPGPP_DRAW_MULTIPLIER); const auto &tileSize = this->actor->getTileSet().getTileSize(); @@ -57,16 +53,13 @@ void ActorView::mouseMoved(tgui::Vector2f pos) { } bool ActorView::leftMousePressed(tgui::Vector2f pos) { - if (this->actor == nullptr) - return false; + if (this->actor == nullptr) return false; const auto &mousePos = getMouseWorldPos(); - if (collisionBox->leftMousePressed(mousePos) && !this->editData) - collisionBox->focused = true; + if (collisionBox->leftMousePressed(mousePos) && !this->editData) collisionBox->focused = true; - if (atlasBox->leftMousePressed(mousePos) && this->editData) - atlasBox->focused = true; + if (atlasBox->leftMousePressed(mousePos) && this->editData) atlasBox->focused = true; return WorldView::leftMousePressed(pos); } @@ -77,8 +70,7 @@ void ActorView::setCollisionRect(const Rectangle &collision) { } void ActorView::leftMouseReleased(tgui::Vector2f pos) { - if (this->actor == nullptr) - return; + if (this->actor == nullptr) return; const auto &mousePos = getMouseWorldPos(); actor->setCollisionRect(collisionBox->leftMouseReleased(mousePos)); @@ -87,8 +79,7 @@ void ActorView::leftMouseReleased(tgui::Vector2f pos) { const auto &tileSize = this->actor->getTileSet().getTileSize(); const auto &rect = atlasBox->leftMouseReleased(mousePos); - this->actor->setAnimationFrame(this->actor->getAnimationDirection(), - this->actor->getCurrentFrame(), + this->actor->setAnimationFrame(this->actor->getAnimationDirection(), this->actor->getCurrentFrame(), {rect.x / tileSize.x, rect.y / tileSize.y}); actorFileView->frameEditor->updateFrameButtons(); @@ -97,12 +88,9 @@ void ActorView::leftMouseReleased(tgui::Vector2f pos) { WorldView::leftMouseReleased(pos); } -void ActorView::setAtlasRect(const Rectangle &rect) { - this->atlasBox->updateRec(rect); -} +void ActorView::setAtlasRect(const Rectangle &rect) { this->atlasBox->updateRec(rect); } void ActorView::drawCanvas() { - if (actor == nullptr || collisionBox == nullptr) { std::cerr << "Importing Error!" << std::endl; return; @@ -110,9 +98,7 @@ void ActorView::drawCanvas() { TileSet &tileSet = actor->getTileSet(); - if (animationCurrentDuration > - animationFrameDuration / DELTATIME_DIFFERENCE && - isPlaying) { + if (animationCurrentDuration > animationFrameDuration / DELTATIME_DIFFERENCE && isPlaying) { actor->update(); animationCurrentDuration = 0.0f; } diff --git a/src/editor/views/codeView.cpp b/src/editor/views/codeView.cpp deleted file mode 100644 index c97ae7a3..00000000 --- a/src/editor/views/codeView.cpp +++ /dev/null @@ -1,56 +0,0 @@ -#include "views/codeView.hpp" -#include "TGUI/Vector2.hpp" -#include "raylib.h" -#include "scriptFile.h" -#include "tree_sitter/api.h" -#include "views/worldView.hpp" -#include - -CodeView::CodeView(ScriptFile *scriptFile) : scriptFile(scriptFile) {} - -CodeView::CodeView() {} - -void CodeView::doTree(TSTreeCursor cursor, TSNode node) { - - auto copy = ts_tree_cursor_copy(&cursor); - bool hasChild = ts_tree_cursor_goto_first_child(©); - if (hasChild) { - this->doTree(copy, ts_tree_cursor_current_node(©)); - } - - auto copy2 = ts_tree_cursor_copy(&cursor); - bool hasSibling = ts_tree_cursor_goto_next_sibling(©2); - if (hasSibling) { - this->doTree(copy2, ts_tree_cursor_current_node(©2)); - } -} - -CodeView::Ptr CodeView::create(ScriptFile *scriptFile) { - return std::make_shared(scriptFile); -} - -CodeView::Ptr CodeView::create() { return std::make_shared(); } - -void CodeView::setCode(ScriptFile *scriptFile) { - this->scriptFile = scriptFile; - - /* - auto parser = ts_parser_new(); - - ts_parser_set_language(parser, tree_sitter_lua()); - auto fileContents = this->scriptFile->getFileContents().c_str(); - - tsTree = ts_parser_parse_string(parser, nullptr, fileContents, - strlen(fileContents)); - - - const auto rootNode = ts_tree_root_node(tsTree); - const auto cursor = ts_tree_cursor_new(rootNode); - - this->doTree(cursor, rootNode); - */ -} - -void CodeView::drawCanvas() { ClearBackground(BLACK); } - -void CodeView::mouseMoved(tgui::Vector2f pos) { WorldView::mouseMoved(pos); } \ No newline at end of file diff --git a/src/editor/views/fontView.cpp b/src/editor/views/fontView.cpp index dea0395a..401ea45d 100644 --- a/src/editor/views/fontView.cpp +++ b/src/editor/views/fontView.cpp @@ -1,9 +1,11 @@ #include "views/fontView.hpp" -#include "raylib.h" -#include "saveables/fontWrapper.hpp" + #include #include +#include "raylib.h" +#include "saveables/fontWrapper.hpp" + FontView::FontView() {} FontView::Ptr FontView::create() { return std::make_shared(); } diff --git a/src/editor/views/imageView.cpp b/src/editor/views/imageView.cpp index 97ae0900..ae8172c6 100644 --- a/src/editor/views/imageView.cpp +++ b/src/editor/views/imageView.cpp @@ -1,4 +1,5 @@ #include "views/imageView.hpp" + #include "raylib.h" #include "saveables/imageWrapper.hpp" diff --git a/src/editor/views/propPreview.cpp b/src/editor/views/propPreview.cpp new file mode 100644 index 00000000..d5f4c77d --- /dev/null +++ b/src/editor/views/propPreview.cpp @@ -0,0 +1,48 @@ +#include "views/propPreview.hpp" + +#include + +#include "components/resizableCanvasBox.hpp" +#include "editor.hpp" +#include "prop.hpp" +#include "raylib.h" +#include "services/translationService.hpp" + +constexpr float MAX_BLINK_FREQ = 30; +constexpr int FONT_SIZE = 18; +constexpr Color OVER_BOUNDS_COLOR = {255, 255, 255, 200}; + +PropPreview::PropPreview() { camera.zoom = 3; } + +void PropPreview::setProp(Prop *prop) { this->prop = prop; } + +void PropPreview::setBox(ResizableCanvasBox *box) { this->referenceToBox = box; } + +void PropPreview::drawCanvas() { + ClearBackground(WHITE); + TranslationService &ts = Editor::instance->getTranslations(); + + auto texture = prop->getTexture(); + auto atlasRect = prop->getAtlasRect(); + auto boxRect = referenceToBox->getRectangle(); + + this->isOverBounds = ((boxRect.x + boxRect.width > texture.width || boxRect.y + boxRect.height > texture.height) || + (boxRect.x < 0 || boxRect.y < 0)); + drawOrigin(); + DrawTexturePro(texture, boxRect, {0, 0, boxRect.width, boxRect.height}, {0, 0}, 0, + {255, 255, 255, static_cast(isOverBounds ? 100 : 255)}); +} + +void PropPreview::drawOverlay() { + if (this->isOverBounds) DrawText("Out of bounds!", 0, 0, FONT_SIZE, RED); + + DrawText("Preview", 0, this->getSize().y - FONT_SIZE, FONT_SIZE, BLACK); +} + +PropPreview::Ptr PropPreview::create() { return std::make_shared(); } + +PropPreview::Ptr PropPreview::create(Prop *prop) { + auto ptr = std::make_shared(); + ptr->setProp(prop); + return ptr; +} diff --git a/src/editor/views/propView.cpp b/src/editor/views/propView.cpp index cd2009ad..3c2d80cf 100644 --- a/src/editor/views/propView.cpp +++ b/src/editor/views/propView.cpp @@ -1,26 +1,27 @@ #include "views/propView.hpp" + +#include +#include + #include "components/resizableCanvasBox.hpp" #include "prop.hpp" #include "raylib.h" #include "views/worldView.hpp" -#include std::string rectTypeToStr(RectType type) { switch (type) { - case ATLAS_RECT: - return "atlasRect"; - case COLLISION_RECT: - return "collisionRect"; - default: - return "unknown"; + case ATLAS_RECT: + return "atlasRect"; + case COLLISION_RECT: + return "collisionRect"; + default: + return "unknown"; } } RectType rectTypeFromStr(const std::string &str) { - if (str == "atlasRect") - return ATLAS_RECT; - if (str == "collisionRect") - return COLLISION_RECT; + if (str == "atlasRect") return ATLAS_RECT; + if (str == "collisionRect") return COLLISION_RECT; return ATLAS_RECT; } @@ -33,8 +34,7 @@ PropView::PropView() { PropView::Ptr PropView::create() { return std::make_shared(); } PropView::Ptr PropView::create(Prop *p) { - if (p == nullptr) - return nullptr; + if (p == nullptr) return nullptr; auto ptr = std::make_shared(); ptr->p = p; ptr->setProp(p); @@ -43,31 +43,24 @@ PropView::Ptr PropView::create(Prop *p) { } void PropView::setProp(Prop *p) { - if (p == nullptr) - return; + if (p == nullptr) return; this->p = p; Rectangle atlasRect = p->getAtlasRect(); Rectangle collisionRect = p->getCollisionRect(); - boxes.push_back(ResizableCanvasBox(rectTypeToStr(RectType::ATLAS_RECT), - atlasRect, BLUE)); - boxes.push_back(ResizableCanvasBox(rectTypeToStr(RectType::COLLISION_RECT), - collisionRect, RED)); + boxes.push_back(ResizableCanvasBox(rectTypeToStr(RectType::ATLAS_RECT), atlasRect, BLUE)); + boxes.push_back(ResizableCanvasBox(rectTypeToStr(RectType::COLLISION_RECT), collisionRect, RED)); } Prop *PropView::getProp() const { return this->p; } void PropView::drawCanvas() { - if (this->p == nullptr) - return; + if (this->p == nullptr) return; ClearBackground(RAYWHITE); Texture2D propTexture = p->getTexture(); - DrawTexturePro( - propTexture, - Rectangle{0, 0, propTexture.width * 1.f, propTexture.height * 1.f}, - Rectangle{0, 0, propTexture.width * 1.f, propTexture.height * 1.f}, - {0, 0}, 0, WHITE); + DrawTexturePro(propTexture, Rectangle{0, 0, propTexture.width * 1.f, propTexture.height * 1.f}, + Rectangle{0, 0, propTexture.width * 1.f, propTexture.height * 1.f}, {0, 0}, 0, WHITE); this->drawOrigin(); @@ -78,13 +71,11 @@ void PropView::drawCanvas() { } void PropView::drawOverlay() { - if (this->p == nullptr) - return; + if (this->p == nullptr) return; } void PropView::mouseMoved(tgui::Vector2f _) { - if (this->p == nullptr) - return; + if (this->p == nullptr) return; Vector2 mousePos = getMouseWorldPos(); for (auto &box : boxes) { box.mouseMoved(mousePos); @@ -93,8 +84,7 @@ void PropView::mouseMoved(tgui::Vector2f _) { } bool PropView::leftMousePressed(tgui::Vector2f _) { - if (this->p == nullptr) - return false; + if (this->p == nullptr) return false; Vector2 mousePos = getMouseWorldPos(); auto focusedIt = boxes.end(); @@ -116,42 +106,51 @@ bool PropView::leftMousePressed(tgui::Vector2f _) { } void PropView::updateAtlasRect(Rectangle r) { - if (this->p == nullptr) - return; + if (this->p == nullptr) return; for (auto &box : boxes) { - if (box.id == rectTypeToStr(RectType::ATLAS_RECT)) - box.updateRec(r); + if (box.id == rectTypeToStr(RectType::ATLAS_RECT)) box.updateRec(r); } p->setAtlasRect(r); } +std::optional PropView::getAtlasRect() { + // NOTE: Can we please switch to an std::map based system? + + // please? + + if (this->p == nullptr) return std::nullopt; + for (auto &box : boxes) { + if (box.id == rectTypeToStr(RectType::ATLAS_RECT)) { + return &box; + } + } + return std::nullopt; +} + void PropView::updateCollisionRect(Rectangle r) { - if (this->p == nullptr) - return; + if (this->p == nullptr) return; for (auto &box : boxes) { - if (box.id == rectTypeToStr(RectType::COLLISION_RECT)) - box.updateRec(r); + if (box.id == rectTypeToStr(RectType::COLLISION_RECT)) box.updateRec(r); } p->setCollisionRect(r); } void PropView::leftMouseReleased(tgui::Vector2f _) { - if (this->p == nullptr) - return; + if (this->p == nullptr) return; Vector2 mousePos = getMouseWorldPos(); for (auto &box : boxes) { Rectangle newRect = box.leftMouseReleased(mousePos); switch (rectTypeFromStr(box.id)) { - case ATLAS_RECT: - p->setAtlasRect(newRect); - onUpdatedAtlasRect.emit(this, newRect); - break; - case COLLISION_RECT: - p->setCollisionRect(newRect); - onUpdatedCollisionRect.emit(this, newRect); - break; - default: - break; + case ATLAS_RECT: + p->setAtlasRect(newRect); + onUpdatedAtlasRect.emit(this, newRect); + break; + case COLLISION_RECT: + p->setCollisionRect(newRect); + onUpdatedCollisionRect.emit(this, newRect); + break; + default: + break; } } WorldView::leftMouseReleased(_); diff --git a/src/editor/views/roomView.cpp b/src/editor/views/roomView.cpp index 1a1f058f..d6a84fdb 100644 --- a/src/editor/views/roomView.cpp +++ b/src/editor/views/roomView.cpp @@ -21,6 +21,7 @@ #include "gamedata.hpp" #include "interactable.hpp" #include "raylib.h" +#include "raymath.h" #include "room.hpp" #include "screens/projectScreen.hpp" #include "tile.hpp" @@ -450,7 +451,22 @@ void RoomView::handleEditPress(tgui::Vector2f pos) { layerVisitor->group->removeAllWidgets(); mj::visit(*layerVisitor, layer); - } + } break; + case RoomLayer::LAYER_ACTORS: { + IVector tileMouse = getTileAtMouse(); + + layerVisitor->actor = nullptr; + layerVisitor->actorName = ""; + for (auto &[name, actor] : room->getActors().getActors()) { + if (Vector2Equals(actor->getTilePosition(), fromIVector(tileMouse))) { + layerVisitor->actor = actor.get(); + layerVisitor->actorName = name; + } + } + + layerVisitor->group->removeAllWidgets(); + mj::visit(*layerVisitor, layer); + } break; default: break; } diff --git a/src/editor/views/tileSetView.cpp b/src/editor/views/tileSetView.cpp index 8359b5e8..12728ab1 100644 --- a/src/editor/views/tileSetView.cpp +++ b/src/editor/views/tileSetView.cpp @@ -1,4 +1,5 @@ #include "views/tileSetView.hpp" + #include "TGUI/Vector2.hpp" #include "gamedata.hpp" #include "raylib.h" @@ -22,17 +23,13 @@ TileSetView::Ptr TileSetView::create(TileSet *tileSet) { return tileSetView; } -void TileSetView::setTileSet(TileSet *newTileSet) { - this->tileSet = newTileSet; -} +void TileSetView::setTileSet(TileSet *newTileSet) { this->tileSet = newTileSet; } TileSet *TileSetView::getTileSet() { return tileSet; } IVector TileSetView::getTileAtMouse() { - return {static_cast((mouseWorldPos.x / (RPGPP_DRAW_MULTIPLIER * - tileSet->getTileWidth()))), - static_cast((mouseWorldPos.y / (RPGPP_DRAW_MULTIPLIER * - tileSet->getTileHeight())))}; + return {static_cast((mouseWorldPos.x / (RPGPP_DRAW_MULTIPLIER * tileSet->getTileWidth()))), + static_cast((mouseWorldPos.y / (RPGPP_DRAW_MULTIPLIER * tileSet->getTileHeight())))}; } IVector TileSetView::getSelectedTile() { return selectedTile; } @@ -46,17 +43,15 @@ void TileSetView::drawOverlay() { const Texture2D &texture = this->tileSet->getTexture(); - Rectangle textureRect = { - 0, 0, static_cast(texture.width * RPGPP_DRAW_MULTIPLIER), - static_cast(texture.height * RPGPP_DRAW_MULTIPLIER)}; + Rectangle textureRect = {0, 0, static_cast(texture.width * RPGPP_DRAW_MULTIPLIER), + static_cast(texture.height * RPGPP_DRAW_MULTIPLIER)}; if (CheckCollisionPointRec(mouseWorldPos, textureRect)) { auto tilePos = getTileAtMouse(); int atlasPosX = tilePos.x; int atlasPosY = tilePos.y; - DrawText(TextFormat("Tile [%i, %i]", atlasPosX, atlasPosY), 8, 8, 32, - BLACK); + DrawText(TextFormat("Tile [%i, %i]", atlasPosX, atlasPosY), 8, 8, 32, BLACK); } } @@ -77,16 +72,13 @@ void TileSetView::drawCanvas() { }; // Draw texture itself - DrawTextureEx(this->tileSet->getTexture(), origin, 0.0f, - RPGPP_DRAW_MULTIPLIER, WHITE); + DrawTextureEx(this->tileSet->getTexture(), origin, 0.0f, RPGPP_DRAW_MULTIPLIER, WHITE); // Draw a grid for (int x = 0; x < atlasSizeInTiles.x; x++) { for (int y = 0; y < atlasSizeInTiles.y; y++) { - Rectangle tileRect = {tileSize.x * x * RPGPP_DRAW_MULTIPLIER, - tileSize.y * y * RPGPP_DRAW_MULTIPLIER, - tileSize.x * RPGPP_DRAW_MULTIPLIER, - tileSize.y * RPGPP_DRAW_MULTIPLIER}; + Rectangle tileRect = {tileSize.x * x * RPGPP_DRAW_MULTIPLIER, tileSize.y * y * RPGPP_DRAW_MULTIPLIER, + tileSize.x * RPGPP_DRAW_MULTIPLIER, tileSize.y * RPGPP_DRAW_MULTIPLIER}; DrawRectangleLinesEx(tileRect, 1.0f, Fade(GRAY, 0.5f)); if (tool != RoomTool::TOOL_NONE) { diff --git a/src/editor/views/worldView.cpp b/src/editor/views/worldView.cpp index eefdb5e6..6420c618 100644 --- a/src/editor/views/worldView.cpp +++ b/src/editor/views/worldView.cpp @@ -1,12 +1,5 @@ #include "views/worldView.hpp" -#include "TGUI/Backend/Renderer/Raylib/CanvasRaylib.hpp" -#include "TGUI/Event.hpp" -#include "TGUI/Vector2.hpp" -#include "TGUI/Widget.hpp" -#include "raylib.h" -#include "raymath.h" -#include "updatable.hpp" #include #include #include @@ -14,9 +7,17 @@ #include #include +#include "TGUI/Backend/Renderer/Raylib/CanvasRaylib.hpp" +#include "TGUI/Cursor.hpp" +#include "TGUI/Event.hpp" +#include "TGUI/Vector2.hpp" +#include "TGUI/Widget.hpp" +#include "raylib.h" +#include "raymath.h" +#include "updatable.hpp" + // TODO: Possible memory leak (Load with no Unload visible) -WorldView::WorldView(const char *typeName, bool initRenderer) - : tgui::CanvasRaylib(typeName, initRenderer) { +WorldView::WorldView(const char *typeName, bool initRenderer) : tgui::CanvasRaylib(typeName, initRenderer) { mouseMiddleButton = false; mouseWorldPos = {0, 0}; @@ -44,18 +45,12 @@ WorldView::Ptr WorldView::copy(const ConstPtr &widget) { } } -tgui::Widget::Ptr WorldView::clone() const { - return std::make_shared(*this); -} +tgui::Widget::Ptr WorldView::clone() const { return std::make_shared(*this); } -void WorldView::setSize(const tgui::Layout2d &size) { - tgui::CanvasRaylib::setSize(size); -} +void WorldView::setSize(const tgui::Layout2d &size) { tgui::CanvasRaylib::setSize(size); } bool WorldView::isMouseOnWidget(tgui::Vector2f pos) const { - return tgui::FloatRect{getPosition().x, getPosition().y, getSize().x, - getSize().y} - .contains(pos); + return tgui::FloatRect{getPosition().x, getPosition().y, getSize().x, getSize().y}.contains(pos); } void WorldView::mouseMoved(tgui::Vector2f pos) { @@ -74,7 +69,7 @@ void WorldView::mouseMoved(tgui::Vector2f pos) { tgui::Widget::mouseMoved(pos); } -constexpr int MAXIMUM_LINE = 10000; +constexpr int MAXIMUM_LINE = 100; void WorldView::drawOrigin() { // since this function is used to draw the origin x-y axis, it's been moved @@ -107,9 +102,7 @@ bool WorldView::leftMousePressed(tgui::Vector2f pos) { return tgui::CanvasRaylib::leftMousePressed(pos); } -void WorldView::leftMouseReleased(tgui::Vector2f pos) { - mouseLeftButton = false; -} +void WorldView::leftMouseReleased(tgui::Vector2f pos) { mouseLeftButton = false; } void WorldView::keyPressed(const tgui::Event::KeyEvent &event) { if (event.control && event.code == tgui::Event::KeyboardKey::Z) { @@ -122,6 +115,8 @@ bool WorldView::canGainFocus() const { return true; } void WorldView::update() { mouseMiddleButton = IsMouseButtonDown(MOUSE_MIDDLE_BUTTON); + setMouseCursor(mouseMiddleButton ? tgui::Cursor::Type::Move : tgui::Cursor::Type::Arrow); + BeginTextureMode(m_textureTarget); BeginMode2D(camera); @@ -137,20 +132,16 @@ void WorldView::drawCanvas() { ClearBackground(RAYWHITE); } void WorldView::drawOverlay() {} -void WorldView::draw(tgui::BackendRenderTarget &target, - const tgui::RenderStates states) const { - constexpr tgui::Borders borders{ - 2}; // Borders are 2 pixels thick on any side +void WorldView::draw(tgui::BackendRenderTarget &target, const tgui::RenderStates states) const { + constexpr tgui::Borders borders{2}; // Borders are 2 pixels thick on any side CanvasRaylib::draw(target, states); - target.drawBorders(states, borders, getSize(), - tgui::Color::applyOpacity(tgui::Color::Black, 0.5f)); + target.drawBorders(states, borders, getSize(), tgui::Color::applyOpacity(tgui::Color::Black, 0.5f)); } Vector2 WorldView::getMouseWorldPos() { return mouseWorldPos; } -std::shared_ptr -WorldView::asUpdatable(const std::shared_ptr &ptr) { +std::shared_ptr WorldView::asUpdatable(const std::shared_ptr &ptr) { return std::dynamic_pointer_cast(ptr); } @@ -158,7 +149,5 @@ void WorldView::setTool(RoomTool newTool) { this->tool = newTool; } bool WorldView::isInView() { // return isMouseOnWidget({GetMousePosition().x, GetMousePosition().y}); - return CheckCollisionPointRec( - GetMousePosition(), - {getPosition().x, getPosition().y, getSize().x, getSize().y}); + return CheckCollisionPointRec(GetMousePosition(), {getPosition().x, getPosition().y, getSize().x, getSize().y}); } diff --git a/src/editor/widgets/codeEditor.cpp b/src/editor/widgets/codeEditor.cpp deleted file mode 100644 index 79173f87..00000000 --- a/src/editor/widgets/codeEditor.cpp +++ /dev/null @@ -1,1144 +0,0 @@ -/* - DEPRECATED -*/ - -#include "widgets/codeEditor.hpp" -#include "TGUI/Backend/Renderer/BackendRenderTarget.hpp" -#include "TGUI/Backend/Renderer/BackendText.hpp" -#include "TGUI/Backend/Window/BackendGui.hpp" -#include "TGUI/Color.hpp" -#include "TGUI/String.hpp" -#include "TGUI/Text.hpp" -#include "TGUI/Vector2.hpp" -#include "TGUI/Widgets/TextArea.hpp" -#include "editor.hpp" -#include "raylib.h" -#include "syntaxHighlighter.hpp" -#include "tree_sitter/tree-sitter-lua.h" -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#include - -using namespace tgui; - -#define CODE_EDITOR_LEFT_COLUMN 100.0f - -// TODO: IMPLEMENT A BETTER SYNTAX COLORS MAP! -std::map SYNTAX_COLORS = { - {"ERROR", {tgui::Color::Red, tgui::TextStyle::Regular}}, - {"local", {tgui::Color::Red, tgui::TextStyle::Regular}}, - {"number", {tgui::Color::Green, tgui::TextStyle::Regular}}, - {"string_content", {tgui::Color::Cyan, tgui::TextStyle::Regular}}, - {"identifier", {tgui::Color::Magenta, tgui::TextStyle::Regular}}, - {"function", {tgui::Color::Yellow, tgui::TextStyle::Regular}}, - {"function_call", {tgui::Color::Yellow, tgui::TextStyle::Regular}}, - {"\"", {tgui::Color::Cyan, tgui::TextStyle::Regular}}, - {"(", {tgui::Color::White, tgui::TextStyle::Regular}}, - {")", {tgui::Color::White, tgui::TextStyle::Regular}}, - {"end", {tgui::Color::Yellow, tgui::TextStyle::Regular}}, - {"--", {tgui::Color(84, 81, 103), tgui::TextStyle::Regular}}, - {"comment_content", {tgui::Color(84, 81, 103), tgui::TextStyle::Regular}}}; - -CodeEditor::CodeEditor() { - - this->syntaxParser = ts_parser_new(); - - ts_parser_set_language(this->syntaxParser, tree_sitter_lua()); - - this->onTextChange.connect([&](const tgui::String &text) { - // this->constructHighlightedText(text, this->highlightTree.size() > 0); - textWhole = constructText(m_text); - }); - - this->setMouseCursor(Cursor::Type::Text); -} - -CodeEditor::~CodeEditor() { - ts_parser_delete(this->syntaxParser); - if (tsTree != nullptr) { - ts_tree_delete(tsTree); - } -} - -tgui::Vector2f CodeEditor::findCharacterPosWhole(std::size_t pos) const { - return textWhole.findCharacterPos(pos); -} - -CodeEditor::Ptr CodeEditor::create() { return std::make_shared(); } - -void CodeEditor::parseNode(const TSTreeCursor &cursor, const TSNode &node, - std::list &list) { - - m_lines = m_text.split("\n"); - - auto nodeStartPoint = ts_node_start_point(node); - auto nodeEndPoint = ts_node_end_point(node); - - if (ts_node_child_count(node) == 0) { - printf("%s. \n", ts_node_type(node)); - - auto row = static_cast(ts_node_start_point(node).row); - auto column = static_cast(ts_node_start_point(node).column); - - if (row > m_lines.size() - 1) { - return; - } - - auto rowString = m_lines[row].toStdString(); - - std::string lineBefore = - TextSubtext(rowString.c_str(), 0, ts_node_start_point(node).column); - - auto textLineBefore = constructText(lineBefore); - - /* - std::string subtext = - TextSubtext(m_text.toStdString().c_str(), ts_node_start_byte(node), - ts_node_end_byte(node)); - - int j = 0; - std::string s = ""; - for (auto c : subtext) { - if (c == '\n') { - if (j != subtext.size() - 1) { - printf("%s \n", s.c_str()); - s = ""; - } - } else { - s.push_back(c); - } - j++; - } - printf("%s \n", s.c_str()); - */ - - auto text = this->constructText(TextSubtext( - m_lines[row].toStdString().c_str(), - ts_node_start_point(node).column, ts_node_end_point(node).column)); - - // auto text = constructText(s); - - if (SYNTAX_COLORS.count(ts_node_type(node)) > 0) { - text.setColor(SYNTAX_COLORS[ts_node_type(node)].color); - } else { - text.setColor(tgui::Color::White); - } - - auto a = textLineBefore.getLineWidth(); - auto b = textLineBefore.getLineHeight() * row; - - EditorHighlighting::TextPiece piece; - piece.text = text; - piece.pos = {a, b}; - piece.nodeStart = ts_node_start_byte(node); - piece.nodeEnd = ts_node_end_byte(node); - - list.push_back(piece); - } - - auto copy = ts_tree_cursor_copy(&cursor); - if (ts_tree_cursor_goto_first_child(©)) - parseNode(copy, ts_tree_cursor_current_node(©), list); - - auto copy2 = ts_tree_cursor_copy(&cursor); - if (ts_tree_cursor_goto_next_sibling(©2)) - parseNode(copy2, ts_tree_cursor_current_node(©2), list); -} - -std::vector -CodeEditor::getStructsFromText(const tgui::String &text_ref) { - std::vector highlighter = {}; - - const auto textStr = text_ref.toStdString(); - const auto constCharStr = textStr.c_str(); - TSTree *syntaxTree = ts_parser_parse_string( - this->syntaxParser, nullptr, constCharStr, strlen(constCharStr)); - - const auto rootNode = ts_tree_root_node(syntaxTree); - const auto cursor = ts_tree_cursor_new(rootNode); - - tsTree = syntaxTree; - - return highlighter; -} - -void CodeEditor::setCode(tgui::String text) { - TextArea::setText(text); - - const auto textStr = getText().toStdString(); - const auto constCharStr = textStr.c_str(); - tsTree = ts_parser_parse_string(this->syntaxParser, nullptr, constCharStr, - strlen(constCharStr)); - - const auto rootNode = ts_tree_root_node(tsTree); - const auto cursor = ts_tree_cursor_new(rootNode); - - // Windows Line Endings Fix. - text.replace("\r\n", "\n"); - m_lines = text.split(U"\n"); - - parseNode(cursor, rootNode, list); -} - -bool CodeEditor::leftMousePressed(tgui::Vector2f pos) { - pos.x -= CODE_EDITOR_LEFT_COLUMN; - return TextArea::leftMousePressed(pos); -} - -void CodeEditor::textEntered(char32_t key) { - if (m_readOnly) - return; - - // Don't allow carriage return characters, they only cause trouble - if (key == '\r') - return; - - // Make sure we don't exceed our maximum characters limit - if ((m_maxChars > 0) && (m_text.length() + 1 > m_maxChars)) - return; - - auto insert = TGUI_LAMBDA_CAPTURE_EQ_THIS() { - deleteSelectedCharacters(); - - const std::size_t caretPosition = getSelectionEnd(); - - m_text.insert(caretPosition, 1, key); - m_lines[m_selEnd.y].insert(m_selEnd.x, 1, key); - - TSInputEdit edit; - edit.start_byte = caretPosition; - edit.start_point = {static_cast(m_selEnd.x), - static_cast(m_selEnd.y)}; - - edit.old_end_byte = caretPosition; - edit.old_end_point = {static_cast(m_selEnd.x), - static_cast(m_selEnd.y)}; - - edit.new_end_byte = caretPosition + 1; - edit.new_end_point = { - static_cast(getColumnAt(caretPosition + 1)), - static_cast(getLineAt(caretPosition + 1))}; - - if (tsTree == nullptr) { - const auto textStr = getText().toStdString(); - const auto constCharStr = textStr.c_str(); - TSTree *syntaxTree = - ts_parser_parse_string(this->syntaxParser, nullptr, - constCharStr, strlen(constCharStr)); - - tsTree = syntaxTree; - } - - // ts_tree_edit(tsTree, &edit); - - const auto textStr = m_text.toStdString(); - const auto constCharStr = textStr.c_str(); - TSTree *syntaxTree = ts_parser_parse_string( - this->syntaxParser, tsTree, constCharStr, strlen(constCharStr)); - - tsTree = syntaxTree; - - const auto rootNode = ts_tree_root_node(tsTree); - const auto cursor = ts_tree_cursor_new(rootNode); - - std::vector highlighter = {}; - // parseNode(cursor, rootNode, highlighter); - - // this->fuck = highlighter; - - list.clear(); - parseNode(cursor, rootNode, list); - - int count = 0; - for (int i = 0; i < getCaretLine(); i++) { - count += m_lines[i].size(); - } - /* - constructHighlightedText(highlighter, count, - count + - m_lines[getLineAt(caretPosition)].size()); - */ - - // Increment the caret position, unless you type a newline at the start - // of a line while that line only existed due to word wrapping - if ((key != U'\n') || (m_selEnd.x > 0) || (m_selEnd.y == 0) || - m_lines[m_selEnd.y - 1].empty() || - (m_text[caretPosition - 1] == U'\n')) { - m_selStart.x++; - m_selEnd.x++; - } - - // Do not emit onCaretPositionChanged signal yet, as it could be - // invalid. - rearrangeText(true, false); - }; - - // If there is a scrollbar then inserting can't go wrong - if (m_verticalScrollbar->getPolicy() != Scrollbar::Policy::Never) { - const auto oldSelEnd = m_selEnd; - insert(); - if (oldSelEnd != m_selEnd) - onCaretPositionChange.emit(this); - } else // There is no scrollbar, the text may not fit - { - // Store the data so that it can be reverted - const auto oldText = m_text; - const auto oldSelStart = m_selStart; - const auto oldSelEnd = m_selEnd; - - // Try to insert the character - insert(); - - // Undo the insert if the text does not fit - if (m_lines.size() > - static_cast(getInnerSize().y / m_lineHeight)) { - m_text = oldText; - m_selStart = oldSelStart; - m_selEnd = oldSelEnd; - - rearrangeText(true); - } - // If the caret position changed, emit signal. - else if (oldSelEnd != m_selEnd) { - onCaretPositionChange.emit(this); - } - } - - // The caret should be visible again - m_caretVisible = true; - m_animationTimeElapsed = {}; - - onTextChange.emit(this, m_text); -} - -void CodeEditor::keyPressed(const tgui::Event::KeyEvent &event) { - if (event.code == Event::KeyboardKey::Backspace) - backspaceKeyPressed(); - else - tgui::TextArea::keyPressed(event); -} - -void CodeEditor::backspaceKeyPressed() { - if (m_readOnly) - return; - - // Check that we did not select any characters - if (m_selStart == m_selEnd) { - const std::size_t pos = getSelectionEnd(); - if (pos > 0) { - if (m_selEnd.x > 0) { - // There is a specific case that we have to watch out for. When - // we are removing the last character on a line which was placed - // there by word wrap and a newline follows this character then - // the caret has to be placed at the line above (before the - // newline) instead of at the same line (after the newline) - if ((m_lines[m_selEnd.y].length() == 1) && (pos > 1) && - (pos < m_text.length()) && (m_text[pos - 2] != '\n') && - (m_text[pos] == '\n') && (m_selEnd.y > 0)) { - m_selEnd.y--; - m_selEnd.x = m_lines[m_selEnd.y].length(); - } else // Just remove the character normally - --m_selEnd.x; - } else // At the beginning of the line - { - if (m_selEnd.y > 0) { - --m_selEnd.y; - m_selEnd.x = m_lines[m_selEnd.y].length(); - - if ((m_text[pos - 1] != '\n') && m_selEnd.x > 0) - --m_selEnd.x; - } - } - - m_selStart = m_selEnd; - - m_text.erase(pos - 1, 1); - - // treesitter - - TSInputEdit edit; - edit.start_byte = pos; - edit.start_point = {static_cast(getColumnAt(pos)), - static_cast(getLineAt(pos))}; - - edit.old_end_byte = pos; - edit.old_end_point = {static_cast(getColumnAt(pos)), - static_cast(getLineAt(pos))}; - - edit.new_end_byte = pos - 1; - edit.new_end_point = {static_cast(getColumnAt(pos - 1)), - static_cast(getLineAt(pos - 1))}; - - if (tsTree == nullptr) { - const auto textStr = getText().toStdString(); - const auto constCharStr = textStr.c_str(); - TSTree *syntaxTree = - ts_parser_parse_string(this->syntaxParser, nullptr, - constCharStr, strlen(constCharStr)); - - tsTree = syntaxTree; - } - - // ts_tree_edit(tsTree, &edit); - - const auto textStr = getText().toStdString(); - const auto constCharStr = textStr.c_str(); - TSTree *syntaxTree = - ts_parser_parse_string(this->syntaxParser, nullptr, - constCharStr, strlen(constCharStr)); - - tsTree = syntaxTree; - - const auto rootNode = ts_tree_root_node(tsTree); - const auto cursor = ts_tree_cursor_new(rootNode); - - list.clear(); - parseNode(cursor, rootNode, list); - - // If the "special case" above passes, and we let rearrangeText() - // emit the onCaretPositionChange signal, the same signal will be - // emitted twice. So prevent sending signal in rearrangeText() and - // always send it manually afterwards. - rearrangeText(true, false); - onCaretPositionChange.emit(this); - } - } else // When you did select some characters then delete them - deleteSelectedCharacters(); - - // The caret should be visible again - m_caretVisible = true; - m_animationTimeElapsed = {}; - - onTextChange.emit(this, m_text); -} - -void CodeEditor::recalculatePositions() { - if (!m_fontCached) - return; - - float textOffset = - Text::getExtraHorizontalPadding(m_fontCached, m_textSizeCached); - - // Calculate the position of the text objects - m_selectionRects.clear(); - m_textBeforeSelection.setPosition( - {textOffset + CODE_EDITOR_LEFT_COLUMN, 0}); - m_defaultText.setPosition({textOffset + CODE_EDITOR_LEFT_COLUMN, 0}); - - if (m_selStart != m_selEnd) { - auto selectionStart = m_selStart; - auto selectionEnd = m_selEnd; - - if ((m_selStart.y > m_selEnd.y) || - ((m_selStart.y == m_selEnd.y) && (m_selStart.x > m_selEnd.x))) - std::swap(selectionStart, selectionEnd); - - float kerningSelectionStart = 0; - if ((selectionStart.x > 0) && - (selectionStart.x < m_lines[selectionStart.y].length())) - kerningSelectionStart = m_fontCached.getKerning( - m_lines[selectionStart.y][selectionStart.x - 1], - m_lines[selectionStart.y][selectionStart.x], m_textSizeCached, - false); - - float kerningSelectionEnd = 0; - if ((selectionEnd.x > 0) && - (selectionEnd.x < m_lines[selectionEnd.y].length())) - kerningSelectionEnd = m_fontCached.getKerning( - m_lines[selectionEnd.y][selectionEnd.x - 1], - m_lines[selectionEnd.y][selectionEnd.x], m_textSizeCached, - false); - - if (selectionStart.x > 0) { - m_textSelection1.setPosition( - {textOffset + - m_textBeforeSelection - .findCharacterPos( - m_textBeforeSelection.getString().length()) - .x + - kerningSelectionStart + CODE_EDITOR_LEFT_COLUMN, - m_textBeforeSelection.getPosition().y + - (selectionStart.y * m_lineHeight)}); - } else - m_textSelection1.setPosition( - {textOffset + CODE_EDITOR_LEFT_COLUMN, - m_textBeforeSelection.getPosition().y + - (selectionStart.y * m_lineHeight)}); - - m_textSelection2.setPosition( - {textOffset + CODE_EDITOR_LEFT_COLUMN, - static_cast((selectionStart.y + 1) * m_lineHeight)}); - - if (!m_textSelection2.getString().empty() || (selectionEnd.x == 0)) { - m_textAfterSelection1.setPosition( - {textOffset + - m_textSelection2 - .findCharacterPos( - m_textSelection2.getString().length()) - .x + - kerningSelectionEnd + CODE_EDITOR_LEFT_COLUMN, - m_textSelection2.getPosition().y + - ((selectionEnd.y - selectionStart.y - 1) * m_lineHeight)}); - } else - m_textAfterSelection1.setPosition( - {m_textSelection1.getPosition().x + - m_textSelection1 - .findCharacterPos( - m_textSelection1.getString().length()) - .x + - kerningSelectionEnd, - m_textSelection1.getPosition().y}); - - m_textAfterSelection2.setPosition( - {textOffset + CODE_EDITOR_LEFT_COLUMN, - static_cast(selectionEnd.y + 1) * m_lineHeight}); - - // Recalculate the selection rectangles - { - m_selectionRects.emplace_back(m_textSelection1.getPosition().x, - static_cast(selectionStart.y) * - m_lineHeight, - 0.f, m_lineHeight); - - if (!m_lines[selectionStart.y].empty()) { - m_selectionRects.back().width = - m_textSelection1 - .findCharacterPos(m_textSelection1.getString().length()) - .x; - - // There is kerning when the selection is on just this line - if (selectionStart.y == selectionEnd.y) - m_selectionRects.back().width += kerningSelectionEnd; - } - - /// TODO: Implement a way to calculate text size without creating a - /// text object? - Text tempText; - tempText.setFont(m_fontCached); - tempText.setCharacterSize(getTextSize()); - for (std::size_t i = selectionStart.y + 1; i < selectionEnd.y; - ++i) { - m_selectionRects.back().width += textOffset; - m_selectionRects.emplace_back( - m_textSelection2.getPosition().x - textOffset, - static_cast(i) * m_lineHeight, textOffset, - m_lineHeight); - - if (!m_lines[i].empty()) { - tempText.setString(m_lines[i]); - m_selectionRects.back().width += - tempText.findCharacterPos(tempText.getString().length()) - .x; - } - } - - if (selectionStart.y != selectionEnd.y) { - m_selectionRects.back().width += textOffset; - - if (!m_textSelection2.getString().empty()) { - tempText.setString( - m_lines[selectionEnd.y].substr(0, selectionEnd.x)); - m_selectionRects.emplace_back( - m_textSelection2.getPosition().x - textOffset, - static_cast(selectionEnd.y) * m_lineHeight, - textOffset + - tempText - .findCharacterPos(tempText.getString().length()) - .x + - kerningSelectionEnd, - m_lineHeight); - } else - m_selectionRects.emplace_back( - 0.f, static_cast(selectionEnd.y) * m_lineHeight, - textOffset, m_lineHeight); - } - } - } - - if (m_parentGui) { - const Vector2f caretPosition = { - m_caretPosition.x + m_bordersCached.getLeft() + - m_paddingCached.getLeft() - - static_cast(m_horizontalScrollbar->getValue()), - m_caretPosition.y + m_bordersCached.getTop() + - m_paddingCached.getTop() - - static_cast(m_verticalScrollbar->getValue())}; - const auto absoluteLineTopPos = - getAbsolutePosition({0, caretPosition.y}); - const float caretHeight = std::max( - m_fontCached.getFontHeight(m_textSizeCached), m_lineHeight); - const FloatRect inputRect = { - absoluteLineTopPos, - getAbsolutePosition({getSize().x, caretPosition.y + caretHeight}) - - absoluteLineTopPos}; - m_parentGui->updateTextCursorPosition( - inputRect, - getAbsolutePosition( - {caretPosition.x + m_caretWidthCached, caretPosition.y})); - } - - recalculateVisibleLines(); -} - -void CodeEditor::updateSelectionTexts() { - // If there is no selection then just put the whole text in - // m_textBeforeSelection - if (m_selStart == m_selEnd) { - String displayedText; - for (const auto &line : m_lines) - displayedText += line + U"\n"; - - m_textBeforeSelection.setString(displayedText); - m_textSelection1.setString(U""); - m_textSelection2.setString(U""); - m_textAfterSelection1.setString(U""); - m_textAfterSelection2.setString(U""); - } else // Some text is selected - { - auto selectionStart = m_selStart; - auto selectionEnd = m_selEnd; - - if ((m_selStart.y > m_selEnd.y) || - ((m_selStart.y == m_selEnd.y) && (m_selStart.x > m_selEnd.x))) - std::swap(selectionStart, selectionEnd); - - // Set the text before the selection - if (selectionStart.y > 0) { - String string; - for (std::size_t i = 0; i < selectionStart.y; ++i) - string += m_lines[i] + U"\n"; - - string += m_lines[selectionStart.y].substr(0, selectionStart.x); - m_textBeforeSelection.setString(string); - } else - m_textBeforeSelection.setString( - m_lines[0].substr(0, selectionStart.x)); - - // Set the selected text - if (m_selStart.y == m_selEnd.y) { - m_textSelection1.setString(m_lines[selectionStart.y].substr( - selectionStart.x, selectionEnd.x - selectionStart.x)); - m_textSelection2.setString(U""); - } else { - m_textSelection1.setString(m_lines[selectionStart.y].substr( - selectionStart.x, - m_lines[selectionStart.y].length() - selectionStart.x)); - - String string; - for (std::size_t i = selectionStart.y + 1; i < selectionEnd.y; ++i) - string += m_lines[i] + U"\n"; - - string += m_lines[selectionEnd.y].substr(0, selectionEnd.x); - - m_textSelection2.setString(string); - } - - // Set the text after the selection - { - m_textAfterSelection1.setString(m_lines[selectionEnd.y].substr( - selectionEnd.x, - m_lines[selectionEnd.y].length() - selectionEnd.x)); - - String string; - for (std::size_t i = selectionEnd.y + 1; i < m_lines.size(); ++i) - string += m_lines[i] + U"\n"; - - m_textAfterSelection2.setString(string); - } - } - - // Check if the caret is located above or below the view - if (m_verticalScrollbar->getPolicy() != Scrollbar::Policy::Never) { - if (m_selEnd.y <= m_topLine) - m_verticalScrollbar->setValue( - static_cast(m_selEnd.y * m_lineHeight)); - else if (m_selEnd.y + 1 >= m_topLine + m_visibleLines) - m_verticalScrollbar->setValue(static_cast( - (m_selEnd.y * m_lineHeight) + - std::max(m_fontCached.getFontHeight(m_textSizeCached), - m_lineHeight) + - Text::getExtraVerticalPadding(m_textSizeCached) - - m_verticalScrollbar->getViewportSize())); - } - - // Position the caret - { - /// TODO: Implement a way to calculate text size without creating a text - /// object? - const float textOffset = - Text::getExtraHorizontalPadding(m_fontCached, m_textSizeCached); - Text tempText; - tempText.setFont(m_fontCached); - tempText.setCharacterSize(getTextSize()); - tempText.setString(m_lines[m_selEnd.y].substr(0, m_selEnd.x)); - - float kerning = 0; - if ((m_selEnd.x > 0) && (m_selEnd.x < m_lines[m_selEnd.y].length())) - kerning = m_fontCached.getKerning( - m_lines[m_selEnd.y][m_selEnd.x - 1], - m_lines[m_selEnd.y][m_selEnd.x], m_textSizeCached, false); - - const float caretLeft = - textOffset + CODE_EDITOR_LEFT_COLUMN + - tempText.findCharacterPos(tempText.getString().length()).x + - kerning; - const float caretTop = static_cast(m_selEnd.y) * m_lineHeight; - m_caretPosition = {caretLeft, caretTop}; - } - - if (m_horizontalScrollbar->getPolicy() != Scrollbar::Policy::Never) { - const unsigned int left = m_horizontalScrollbar->getValue(); - if (m_caretPosition.x <= left) { - unsigned int newValue = static_cast(std::max( - 0, static_cast(m_caretPosition.x - - (Text::getExtraHorizontalPadding( - m_fontCached, m_textSizeCached) * - 2)))); - m_horizontalScrollbar->setValue(newValue); - } else if (m_caretPosition.x > - (left + m_horizontalScrollbar->getViewportSize())) { - unsigned int newValue = static_cast( - m_caretPosition.x + - (Text::getExtraHorizontalPadding(m_fontCached, - m_textSizeCached) * - 2) - - m_horizontalScrollbar->getViewportSize()); - m_horizontalScrollbar->setValue(newValue); - } - } - - recalculatePositions(); - - // Send an event when the selection changed - if ((m_selStart != m_lastSelection.first) || - (m_selEnd != m_lastSelection.second)) { - // Only send the event when there is an actual change, not when the - // caret position moved - if ((m_selStart != m_selEnd) || - (m_lastSelection.first != m_lastSelection.second)) - onSelectionChange.emit(this); - - m_lastSelection.first = m_selStart; - m_lastSelection.second = m_selEnd; - } -} - -void CodeEditor::mouseMoved(tgui::Vector2f pos) { - pos -= getPosition(); - - if (!m_mouseHover) - mouseEnteredWidget(); - - // The mouse has moved so a double click is no longer possible - m_possibleDoubleClick = false; - - // Check if the mouse event should go to the vertical scrollbar - if (m_verticalScrollbar->isShown() && - (m_verticalScrollbar->isMouseDown() || - m_verticalScrollbar->isMouseOnWidget(pos))) { - m_verticalScrollbar->mouseMoved(pos); - recalculateVisibleLines(); - } - - // Check if the mouse event should go to the horizontal scrollbar - else if (m_horizontalScrollbar->isShown() && - (m_horizontalScrollbar->isMouseDown() || - m_horizontalScrollbar->isMouseOnWidget(pos))) { - m_horizontalScrollbar->mouseMoved(pos); - } - - // If the mouse is held down then you are selecting text - else if (m_mouseDown) { - auto caretPosition = findCaretPosition(pos); - const auto oldSelEnd = m_selEnd; - - if (caretPosition != m_selEnd) { - m_selEnd = caretPosition; - updateSelectionTexts(); - } - - // Check if the caret is located above or below the view - if (m_verticalScrollbar->getViewportSize() < - m_verticalScrollbar->getMaximum()) { - if (m_selEnd.y <= m_topLine) - m_verticalScrollbar->setValue( - static_cast(m_selEnd.y * m_lineHeight)); - else if (m_selEnd.y + 1 >= m_topLine + m_visibleLines) - m_verticalScrollbar->setValue(static_cast( - ((m_selEnd.y + 1) * m_lineHeight) - - m_verticalScrollbar->getViewportSize())); - - recalculateVisibleLines(); - } - - if (oldSelEnd != m_selEnd) - onCaretPositionChange.emit(this); - } - - // Inform the scrollbars that the mouse is not on them - else { - m_verticalScrollbar->mouseNoLongerOnWidget(); - m_horizontalScrollbar->mouseNoLongerOnWidget(); - } -} - -tgui::Vector2 -CodeEditor::findCaretPosition(tgui::Vector2f position) const { - position.x -= m_bordersCached.getLeft() + m_paddingCached.getLeft(); - position.y -= m_bordersCached.getTop() + m_paddingCached.getTop(); - - position.x -= CODE_EDITOR_LEFT_COLUMN; - - // Don't continue when line height is 0 or when there is no font yet - if ((m_lineHeight == 0) || (m_fontCached == nullptr)) - return {m_lines[m_lines.size() - 1].size(), m_lines.size() - 1}; - - // Find on which line the mouse is - std::size_t lineNumber; - if (m_verticalScrollbar->getViewportSize() < - m_verticalScrollbar->getMaximum()) { - if (position.y + m_verticalScrollbar->getValue() < 0) - return {0, 0}; - - lineNumber = static_cast(std::floor( - (position.y + m_verticalScrollbar->getValue()) / m_lineHeight)); - } else { - if (position.y < 0) - return {0, 0}; - - lineNumber = - static_cast(std::floor(position.y / m_lineHeight)); - } - - // Check if you clicked behind everything - if (lineNumber + 1 > m_lines.size()) - return {m_lines[m_lines.size() - 1].size(), m_lines.size() - 1}; - - // Find between which character the mouse is standing - float width = - Text::getExtraHorizontalPadding(m_fontCached, m_textSizeCached) - - m_horizontalScrollbar->getValue(); - char32_t prevChar = 0; - for (std::size_t i = 0; i < m_lines[lineNumber].size(); ++i) { - float charWidth; - const char32_t curChar = m_lines[lineNumber][i]; - // if (curChar == U'\n') - // return Vector2(m_lines[lineNumber].getSize() - 1, - // lineNumber); // TextArea strips newlines but this code is kept - // for when this function is generalized - // else - if (curChar == U'\t') - charWidth = - static_cast( - m_fontCached.getGlyph(' ', getTextSize(), false).advance) * - 4; - else - charWidth = static_cast( - m_fontCached.getGlyph(curChar, getTextSize(), false).advance); - - const float kerning = - m_fontCached.getKerning(prevChar, curChar, getTextSize(), false); - if (width + charWidth + kerning <= position.x) - width += charWidth + kerning; - else { - if (position.x < width + kerning + (charWidth / 2.0f)) - return {i, lineNumber}; - else - return {i + 1, lineNumber}; - } - - prevChar = curChar; - } - - // You clicked behind the last character - return {m_lines[lineNumber].length(), lineNumber}; -} - -bool CodeEditor::scrolled(float delta, tgui::Vector2f pos, bool touch) { - const bool horizontalScrollbarCanMove = - (m_horizontalScrollbar->getViewportSize() < - m_horizontalScrollbar->getMaximum()); - const bool verticalScrollbarCanMove = - (m_verticalScrollbar->getViewportSize() < - m_verticalScrollbar->getMaximum()); - - bool scrollbarMoved = false; - if (horizontalScrollbarCanMove && !touch && - (!verticalScrollbarCanMove || - m_horizontalScrollbar->isMouseOnWidget(pos - getPosition()) || - IsKeyReleased(KEY_LEFT_SHIFT))) { - scrollbarMoved = - m_horizontalScrollbar->scrolled(delta, pos - getPosition(), touch); - } else if (verticalScrollbarCanMove) { - scrollbarMoved = - m_verticalScrollbar->scrolled(delta, pos - getPosition(), touch); - } - - if (scrollbarMoved) - recalculateVisibleLines(); - - return scrollbarMoved; -} - -void CodeEditor::recalculateVisibleLines() { - if (m_lineHeight == 0) - return; - - const float horiScrollOffset = m_horizontalScrollbar->isShown() - ? m_horizontalScrollbar->getSize().y - : 0.f; - m_visibleLines = - std::min(static_cast((getInnerSize().y - - m_paddingCached.getTopPlusBottom() - - horiScrollOffset) / - m_lineHeight), - m_lines.size()); - - // Store which area is visible - if (m_verticalScrollbar->getViewportSize() < - m_verticalScrollbar->getMaximum()) { - m_topLine = static_cast(m_verticalScrollbar->getValue() / - m_lineHeight); - - // The scrollbar may be standing between lines in which case one more - // line is visible - if (((static_cast(getInnerSize().y - - m_paddingCached.getTopPlusBottom() - - horiScrollOffset) % - static_cast(m_lineHeight)) != 0) || - ((m_verticalScrollbar->getValue() % - static_cast(m_lineHeight)) != 0)) - m_visibleLines++; - } else // There is no vertical scrollbar - { - m_topLine = 0; - m_visibleLines = std::min( - static_cast((getInnerSize().y - - m_paddingCached.getTopPlusBottom() - - horiScrollOffset) / - m_lineHeight), - m_lines.size()); - } - - if (m_horizontalScrollbar->isShown()) - m_horizontalScrollbar->setPosition( - m_bordersCached.getLeft(), getSize().y - - m_bordersCached.getBottom() - - m_horizontalScrollbar->getSize().y); - - if (m_verticalScrollbar->isShown()) - m_verticalScrollbar->setPosition({getSize().x - - m_bordersCached.getRight() - - m_verticalScrollbar->getSize().x, - m_bordersCached.getTop()}); -} - -void CodeEditor::draw(BackendRenderTarget &target, RenderStates states) const { - const RenderStates statesForScrollbar = states; - - target.drawFilledRect(states, getInnerSize(), tgui::Color::Black); - const auto &innerSize = getInnerSize(); - const auto lines = this->m_text.split("\n"); - - const auto oldStates = states; - - states.transform.translate( - {m_paddingCached.getLeft(), m_paddingCached.getTop()}); - states.transform.translate( - {-static_cast(m_horizontalScrollbar->getValue()), - -static_cast(m_verticalScrollbar->getValue())}); - - for (int i = 0; i < lines.size(); i++) { - // Text lineIndex = this->constructText(std::to_string(i + 1)); - Text lineIndex; - lineIndex.setFont(m_textAfterSelection1.getFont()); - lineIndex.setCharacterSize(m_textSize); - lineIndex.setString(std::to_string(i + 1)); - lineIndex.setColor(tgui::Color::White); - lineIndex.setPosition( - {CODE_EDITOR_LEFT_COLUMN - lineIndex.getLineWidth(), 0}); - target.drawText(states, lineIndex); - - if (this->getCaretLine() == i + 1 && m_selectionRects.empty()) { - target.drawFilledRect( - states, {m_size.x.getValue(), lineIndex.getLineHeight()}, - tgui::Color{255, 255, 255, 50}); - } - states.transform.translate({0, lineIndex.getLineHeight()}); - } - - states = oldStates; - - { - states.transform.translate( - {m_paddingCached.getLeft(), m_paddingCached.getTop()}); - - float clipWidth = getInnerSize().x - m_paddingCached.getLeftPlusRight(); - if (m_verticalScrollbar->isShown()) - clipWidth -= m_verticalScrollbar->getSize().x; - - float clipHeight = - getInnerSize().y - m_paddingCached.getTopPlusBottom(); - if (m_horizontalScrollbar->isShown()) - clipHeight -= m_horizontalScrollbar->getSize().y; - - target.addClippingLayer(states, {{}, {clipWidth, clipHeight}}); - - // Move the text according to the scrollars - states.transform.translate( - {-static_cast(m_horizontalScrollbar->getValue()), - -static_cast(m_verticalScrollbar->getValue())}); - - // Draw the background of the selected text - for (const auto &selectionRect : m_selectionRects) { - - auto leftSelection = - max(selectionRect.left, CODE_EDITOR_LEFT_COLUMN); - states.transform.translate({leftSelection, selectionRect.top}); - target.drawFilledRect( - states, - {selectionRect.width, - selectionRect.height + - (std::max(m_fontCached.getFontHeight(m_textSizeCached), - m_lineHeight) - - m_lineHeight)}, - tgui::Color::applyOpacity(m_selectedTextBackgroundColorCached, - m_opacityCached)); - states.transform.translate({-leftSelection, -selectionRect.top}); - } - - // Draw the text - if (m_text.empty()) - target.drawText(states, m_defaultText); - else { - - if (m_selStart == m_selEnd) - states.transform.translate({CODE_EDITOR_LEFT_COLUMN, 0}); - - Vector2f offsetPos = {0, 0}; - - if (m_selStart != m_selEnd) { - states.transform.translate({CODE_EDITOR_LEFT_COLUMN, 0}); - states.transform.translate({m_paddingCached.getLeft(), 0}); - } - - for (auto &textPiece : list) { - states.transform.translate(textPiece.pos); - if ((textPiece.pos.y >= m_verticalScrollbar->getValue()) && - (textPiece.pos.y < - m_verticalScrollbar->getValue() + clipHeight)) { - target.drawText(states, textPiece.text); - } - states.transform.translate(-textPiece.pos); - } - - if (m_selStart != m_selEnd) { - states.transform.translate({-CODE_EDITOR_LEFT_COLUMN, 0}); - states.transform.translate({-m_paddingCached.getLeft(), 0}); - } - states.transform.translate(-offsetPos); - - if (m_selStart == m_selEnd) - states.transform.translate({-CODE_EDITOR_LEFT_COLUMN, 0}); - } - - // Only draw the caret when needed - if (m_focused && m_caretVisible && (m_caretWidthCached > 0)) { - const float caretHeight = std::max( - m_fontCached.getFontHeight(m_textSizeCached), m_lineHeight); - states.transform.translate( - {std::ceil(m_caretPosition.x - (m_caretWidthCached / 2.f)), - m_caretPosition.y}); - if (m_selStart == m_selEnd) { - states.transform.translate({CODE_EDITOR_LEFT_COLUMN, 0}); - } - target.drawFilledRect( - states, {m_caretWidthCached, caretHeight}, - tgui::Color::applyOpacity(m_caretColorCached, m_opacityCached)); - if (m_selStart == m_selEnd) { - states.transform.translate({-CODE_EDITOR_LEFT_COLUMN, 0}); - } - } - - target.removeClippingLayer(); - } - - // Draw the scrollbars if needed - if (m_verticalScrollbar->isShown()) - m_verticalScrollbar->draw(target, statesForScrollbar); - - if (m_horizontalScrollbar->isShown()) - m_horizontalScrollbar->draw(target, statesForScrollbar); -} - -Text CodeEditor::constructText(const tgui::String &text, - const Vector2f position) const { - auto cloneText = Text{}; - - cloneText.setFont(m_fontCached); - cloneText.setColor(tgui::Color::White); - cloneText.setString(text); - cloneText.setPosition(position); - cloneText.setCharacterSize(m_textSize); - - return cloneText; -} - -Text CodeEditor::constructText(const tgui::String &text) const { - auto cloneText = Text{}; - - cloneText.setFont(m_fontCached); - cloneText.setColor(tgui::Color::White); - cloneText.setString(text); - cloneText.setCharacterSize(m_textSize); - - return cloneText; -} - -Text CodeEditor::constructText(const tgui::String &text, - const tgui::Color &color) const { - auto cloneText = Text{}; - - cloneText.setFont(m_fontCached); - cloneText.setColor(color); - cloneText.setString(text); - cloneText.setCharacterSize(m_textSize); - - return cloneText; -} - -bool CodeEditor::canGainFocus() const { return true; } - -std::size_t CodeEditor::getColumnAt(std::size_t a) const { - const auto caret = a; - if (caret == 0) - return 1; - auto lineStart = m_text.rfind('\n', caret - 1); - if (lineStart == String::npos) - return caret + 1; - else - return caret - lineStart; -} - -std::size_t CodeEditor::getLineAt(std::size_t a) const { - if (const auto caret = a; caret == 0) - return 1; - else - return m_text.substr(0, caret).count('\n') + 1; -} diff --git a/src/editor/widgets/dialogueEditor.cpp b/src/editor/widgets/dialogueEditor.cpp new file mode 100644 index 00000000..ad8d8ed5 --- /dev/null +++ b/src/editor/widgets/dialogueEditor.cpp @@ -0,0 +1,102 @@ +#include "widgets/dialogueEditor.hpp" + +#include +#include +#include +#include + +constexpr const char *spaceLiteral{" "}; + +#include "TGUI/String.hpp" + +DialogueEditor::Ptr DialogueEditor::create() { return std::make_shared(); } + +DialogueEditor::DialogueEditor() { + this->onSelectionChange.connect([&] { + if (!this->isFocused()) return; + + this->formattingSelectionStart = this->getSelectionStart(); + this->formattingSelectionEnd = this->getSelectionEnd(); + this->selectedText = this->getSelectedText(); + }); +} + +bool DialogueEditor::isTextNonEditable(std::string &tagName) { return this->selectedText.contains(tagName); } + +void DialogueEditor::setTextAndReset(std::string text) { + this->selectedText = ""; + this->setText(text); +} + +void DialogueEditor::fixSelectionRange() { + // This fixes an interesting TGUI issue where the formattingSelectionStart can sometimes be the end of the + // selection. Thanks TGUI for being an awesome GUI library. .w. - thefirey33, 2026 + + if (this->formattingSelectionStart > this->formattingSelectionEnd) { + auto selectionEnd = this->formattingSelectionEnd; + + this->formattingSelectionEnd = this->formattingSelectionStart; + this->formattingSelectionStart = selectionEnd; + } +} + +void DialogueEditor::addXmlTag(std::string tagName) { + this->fixSelectionRange(); + + if (this->isTextNonEditable(tagName)) return; + + auto text = this->getText(); + + std::stringstream ss{}; + + if (this->getSelectionStart() >= this->getSelectionEnd()) { + ss << text; + ss << "<" << tagName << ">" << "" << ""; + } else { + ss << text.substr(0, this->formattingSelectionStart); + ss << "<" << tagName << ">" << this->selectedText << ""; + ss << text.substr(this->formattingSelectionEnd); + } + + this->setTextAndReset(ss.str()); +} + +void DialogueEditor::addXmlTagWithProperties(std::string tagName, std::vector properties) { + this->fixSelectionRange(); + + if (this->isTextNonEditable(tagName)) return; + + auto text = this->getText(); + + std::stringstream ss{}; + + if (this->getSelectionStart() >= this->getSelectionEnd() || this->getSelectedText().empty()) { + ss << text; + } else { + ss << text.substr(0, this->formattingSelectionStart); + } + + ss << "<" << tagName << spaceLiteral; + + for (int i = 0; i < properties.size(); i++) { + auto &val = properties[i]; + + /** + * Construct an XML tag property string in the format "name=\"value\"" with a space separator + * between properties, except for the last one. + * + * This is very confusing, i know. + */ + ss << val.propertyName << "=\"" << val.propertyValue << "\"" + << (i < properties.size() - 1 ? spaceLiteral : std::string{}); + } + + if (this->getSelectionStart() >= this->getSelectionEnd() || this->getSelectedText().empty()) { + ss << ">" << "" << ""; + } else { + ss << ">" << this->selectedText << ""; + ss << text.substr(this->formattingSelectionEnd); + } + + this->setTextAndReset(ss.str()); +} diff --git a/src/editor/widgets/fileChooser.cpp b/src/editor/widgets/fileChooser.cpp index 18df4d09..bfc41e46 100644 --- a/src/editor/widgets/fileChooser.cpp +++ b/src/editor/widgets/fileChooser.cpp @@ -1,4 +1,5 @@ #include "widgets/fileChooser.hpp" + #include "TGUI/String.hpp" #include "TGUI/SubwidgetContainer.hpp" #include "TGUI/Widgets/BitmapButton.hpp" @@ -6,19 +7,14 @@ #include "bindTranslation.hpp" #include "editor.hpp" #include "raylib.h" -FileChooser::FileChooser(const char *typeName, bool initRenderer) - : tgui::SubwidgetContainer(typeName, initRenderer) { - +FileChooser::FileChooser(const char *typeName, bool initRenderer) : tgui::SubwidgetContainer(typeName, initRenderer) { TranslationService &tService = Editor::instance->getTranslations(); chosenPathLabel = tgui::EditBox::create(); - bindTranslation(chosenPathLabel, - "widget.filechooser.select_a_file", - &tgui::EditBox::setText); + bindTranslation(chosenPathLabel, "widget.filechooser.select_a_file", &tgui::EditBox::setText); chosenPathLabel->setReadOnly(true); chosenPathLabel->setEnabled(false); iconButton = tgui::BitmapButton::create(); - auto iconTexture = tgui::Texture( - Editor::instance->getFs().getResourcePath("open_folder.png")); + auto iconTexture = tgui::Texture(Editor::instance->getFs().getResourcePath("open_folder.png")); iconButton->setImageScaling(0.95); iconButton->setImage(iconTexture); @@ -32,8 +28,7 @@ FileChooser::FileChooser(const char *typeName, bool initRenderer) fileDialog->setFileTypeFilters(pathFilters); fileDialog->setSelectingDirectory(selectingDirectory); fileDialog->onFileSelect([this](const tgui::String &path) { - chosenPathLabel->setText( - std::string(GetFileName(path.toStdString().c_str()))); + chosenPathLabel->setText(std::string(GetFileName(path.toStdString().c_str()))); chosenPath = path; }); @@ -46,9 +41,7 @@ FileChooser::FileChooser(const char *typeName, bool initRenderer) updateSize(); } -FileChooser::Ptr FileChooser::create() { - return std::make_shared(); -} +FileChooser::Ptr FileChooser::create() { return std::make_shared(); } FileChooser::Ptr FileChooser::copy(FileChooser::ConstPtr widget) { if (widget) @@ -57,9 +50,7 @@ FileChooser::Ptr FileChooser::copy(FileChooser::ConstPtr widget) { return nullptr; } -tgui::Widget::Ptr FileChooser::clone() const { - return std::make_shared(*this); -} +tgui::Widget::Ptr FileChooser::clone() const { return std::make_shared(*this); } void FileChooser::setSize(const tgui::Layout2d &size) { tgui::SubwidgetContainer::setSize(size); @@ -76,6 +67,4 @@ void FileChooser::updateSize() { tgui::String &FileChooser::getChosenPath() { return chosenPath; } -void FileChooser::setSelectingDirectory(bool selectingDirectory) { - this->selectingDirectory = selectingDirectory; -} +void FileChooser::setSelectingDirectory(bool selectingDirectory) { this->selectingDirectory = selectingDirectory; } diff --git a/src/editor/widgets/fileTab.cpp b/src/editor/widgets/fileTab.cpp index 3b602641..a2ab7c6d 100644 --- a/src/editor/widgets/fileTab.cpp +++ b/src/editor/widgets/fileTab.cpp @@ -1,4 +1,10 @@ #include "widgets/fileTab.hpp" + +#include +#include +#include +#include + #include "TGUI/Color.hpp" #include "TGUI/Loading/Theme.hpp" #include "TGUI/Sprite.hpp" @@ -10,26 +16,18 @@ #include "editor.hpp" #include "fileTabRenderer.hpp" #include "raylib.h" -#include -#include -#include -#include using namespace tgui; -FileTab::FileTab(const char *typeName, bool initRenderer) - : tgui::Tabs(typeName, false) { - m_distanceToSideCached = (std::round( - Text::getLineHeight(m_fontCached, getGlobalTextSize()) * 2.f)); +FileTab::FileTab(const char *typeName, bool initRenderer) : tgui::Tabs(typeName, false) { + m_distanceToSideCached = (std::round(Text::getLineHeight(m_fontCached, getGlobalTextSize()) * 2.f)); if (initRenderer) { m_renderer = aurora::makeCopied(); setRenderer(tgui::Theme::getDefault()->getRendererNoThrow("Tabs")); setTextSize(getGlobalTextSize()); - setTabHeight( - std::round(Text::getLineHeight(m_fontCached, m_textSizeCached) * - 1.25f) + - m_bordersCached.getTopPlusBottom()); + setTabHeight(std::round(Text::getLineHeight(m_fontCached, m_textSizeCached) * 1.25f) + + m_bordersCached.getTopPlusBottom()); } tooltip = Tooltip::create(""); // setToolTip(tooltip); @@ -60,23 +58,19 @@ bool FileTab::leftMousePressed(Vector2f pos) { float tabStart = 0.0f; float tabEnd = m_bordersCached.getLeft() / 2.f; for (std::size_t i = 0; i < m_tabs.size(); ++i) { - if (!m_tabs[i].visible) - continue; + if (!m_tabs[i].visible) continue; // Append the width of the tab - tabEnd += (m_bordersCached.getLeft() / 2.f) + m_tabs[i].width + - (m_bordersCached.getRight() / 2.0f); + tabEnd += (m_bordersCached.getLeft() / 2.f) + m_tabs[i].width + (m_bordersCached.getRight() / 2.0f); // If the mouse went down on this tab then select it - if (pos.x >= tabStart && - pos.x < tabEnd - CLOSE_BUTTON_SIZE - MARGIN_LR) { + if (pos.x >= tabStart && pos.x < tabEnd - CLOSE_BUTTON_SIZE - MARGIN_LR) { select(i); isHoldingMouse = true; startMousePos = pos; draggedTab = i; break; - } else if (pos.x >= tabStart + (m_tabs[i].width - MARGIN_LR - - CLOSE_BUTTON_SIZE) && + } else if (pos.x >= tabStart + (m_tabs[i].width - MARGIN_LR - CLOSE_BUTTON_SIZE) && pos.x < tabEnd - MARGIN_LR) { closeAndOpenNextTab(i); break; @@ -92,8 +86,8 @@ void FileTab::manualMouseMoved(tgui::Vector2f pos) { Tabs::mouseMoved(pos); pos -= getPosition(); deltaMousePos = pos - startMousePos + offsetMousePos; - if (isHoldingMouse and (abs(deltaMousePos.x) >= BUFFER_BEFORE_TAB_MOVE.x or - abs(deltaMousePos.y) >= BUFFER_BEFORE_TAB_MOVE.y)) { + if (isHoldingMouse and + (abs(deltaMousePos.x) >= BUFFER_BEFORE_TAB_MOVE.x or abs(deltaMousePos.y) >= BUFFER_BEFORE_TAB_MOVE.y)) { isDragging = true; } @@ -102,30 +96,22 @@ void FileTab::manualMouseMoved(tgui::Vector2f pos) { if (isDragging) { SetMouseCursor(MOUSE_CURSOR_RESIZE_ALL); cursorModified = true; - if (draggedTab != m_hoveringTab and m_hoveringTab >= 0 and - swappedTab == -1) { + if (draggedTab != m_hoveringTab and m_hoveringTab >= 0 and swappedTab == -1) { // adds the width between the currently hovering tab and the dragged // tab not counting the dragged tab - for (int i = std::min(m_hoveringTab, draggedTab); - i <= std::max(m_hoveringTab, draggedTab); i++) { - if (i == draggedTab) - continue; - offsetMousePos.x -= - m_tabs[i].width * // width of the hovered tab - (deltaMousePos.x / - abs(deltaMousePos.x)); // direction of the drag + for (int i = std::min(m_hoveringTab, draggedTab); i <= std::max(m_hoveringTab, draggedTab); i++) { + if (i == draggedTab) continue; + offsetMousePos.x -= m_tabs[i].width * // width of the hovered tab + (deltaMousePos.x / abs(deltaMousePos.x)); // direction of the drag } - deltaMousePos = pos - startMousePos + - offsetMousePos; // value is updated immediately to - // avoid flickering + deltaMousePos = pos - startMousePos + offsetMousePos; // value is updated immediately to + // avoid flickering swappedTab = draggedTab; if (draggedTab < m_hoveringTab) { - std::rotate(m_tabs.begin() + draggedTab, - m_tabs.begin() + draggedTab + 1, + std::rotate(m_tabs.begin() + draggedTab, m_tabs.begin() + draggedTab + 1, m_tabs.begin() + m_hoveringTab + 1); } else if (draggedTab > m_hoveringTab) { - std::rotate(m_tabs.begin() + m_hoveringTab, - m_tabs.begin() + draggedTab, + std::rotate(m_tabs.begin() + m_hoveringTab, m_tabs.begin() + draggedTab, m_tabs.begin() + draggedTab + 1); } draggedTab = m_hoveringTab; @@ -162,20 +148,17 @@ void FileTab::leftMouseReleased(tgui::Vector2f pos) { } void FileTab::closeCurrentTab() { - if (m_selectedTab == -1) - return; + if (m_selectedTab == -1) return; closeAndOpenNextTab(m_selectedTab); } bool FileTab::select(std::size_t index) { // Don't select a tab that is already selected - if (m_selectedTab == static_cast(index)) - return true; + if (m_selectedTab == static_cast(index)) return true; // If the index is too high or if the tab is invisible or disabled then we // can't select it - if ((index >= m_tabs.size()) || !m_enabled || !m_tabs[index].visible || - !m_tabs[index].enabled) { + if ((index >= m_tabs.size()) || !m_enabled || !m_tabs[index].visible || !m_tabs[index].enabled) { deselect(); return false; } @@ -190,8 +173,7 @@ bool FileTab::select(std::size_t index) { return true; } -size_t FileTab::addFileTab(const std::string &path, - const std::string &fileName) { +size_t FileTab::addFileTab(const std::string &path, const std::string &fileName) { size_t tabIdxToInsert = m_selectedTab; if (tabIdxToInsert == -1) { tabIdxToInsert = 0; @@ -212,29 +194,22 @@ size_t FileTab::addFileTab(const std::string &path, return tabIdxToInsert; } -void FileTab::renderTab(tgui::BackendRenderTarget &target, - tgui::RenderStates &states, int i, bool roundedCorners, - float borderWidth, float usableHeight, - tgui::Sprite &close) const { - if (!m_tabs[i].visible) - return; +void FileTab::renderTab(tgui::BackendRenderTarget &target, tgui::RenderStates &states, int i, bool roundedCorners, + float borderWidth, float usableHeight, tgui::Sprite &close) const { + if (!m_tabs[i].visible) return; RenderStates textStates = states; - if (roundedCorners) - textStates.transform.translate({0, m_bordersCached.getTop()}); + if (roundedCorners) textStates.transform.translate({0, m_bordersCached.getTop()}); tgui::Color backgroundColor; - if ((!m_enabled || !m_tabs[i].enabled) && - m_backgroundColorDisabledCached.isSet()) + if ((!m_enabled || !m_tabs[i].enabled) && m_backgroundColorDisabledCached.isSet()) backgroundColor = m_backgroundColorDisabledCached; else if (m_selectedTab == static_cast(i)) { - if ((m_hoveringTab == static_cast(i)) && - m_selectedBackgroundColorHoverCached.isSet()) + if ((m_hoveringTab == static_cast(i)) && m_selectedBackgroundColorHoverCached.isSet()) backgroundColor = m_selectedBackgroundColorHoverCached; else backgroundColor = m_selectedBackgroundColorCached; - } else if ((m_hoveringTab == static_cast(i)) && - m_backgroundColorHoverCached.isSet()) + } else if ((m_hoveringTab == static_cast(i)) && m_backgroundColorHoverCached.isSet()) backgroundColor = m_backgroundColorHoverCached; else backgroundColor = m_backgroundColorCached; @@ -243,26 +218,22 @@ void FileTab::renderTab(tgui::BackendRenderTarget &target, const Sprite *spriteTab = nullptr; if ((!m_enabled || !m_tabs[i].enabled) && m_spriteDisabledTab.isSet()) spriteTab = &m_spriteDisabledTab; - else if ((m_selectedTab == static_cast(i)) && - m_spriteSelectedTab.isSet()) { - if ((m_hoveringTab == static_cast(i)) && - m_spriteSelectedTabHover.isSet()) + else if ((m_selectedTab == static_cast(i)) && m_spriteSelectedTab.isSet()) { + if ((m_hoveringTab == static_cast(i)) && m_spriteSelectedTabHover.isSet()) spriteTab = &m_spriteSelectedTabHover; else spriteTab = &m_spriteSelectedTab; - } else if ((m_hoveringTab == static_cast(i)) && - m_spriteTabHover.isSet()) + } else if ((m_hoveringTab == static_cast(i)) && m_spriteTabHover.isSet()) spriteTab = &m_spriteTabHover; else if (m_spriteTab.isSet()) spriteTab = &m_spriteTab; if (roundedCorners) { states.transform.translate({-borderWidth, 0}); - target.drawRoundedRectangle( - states, {m_tabs[i].width + (2 * borderWidth), getSize().y}, - tgui::Color::applyOpacity(backgroundColor, m_opacityCached), - m_roundedBorderRadiusCached, m_bordersCached, - tgui::Color::applyOpacity(m_borderColorCached, m_opacityCached)); + target.drawRoundedRectangle(states, {m_tabs[i].width + (2 * borderWidth), getSize().y}, + tgui::Color::applyOpacity(backgroundColor, m_opacityCached), + m_roundedBorderRadiusCached, m_bordersCached, + tgui::Color::applyOpacity(m_borderColorCached, m_opacityCached)); states.transform.translate({m_tabs[i].width + 2 * borderWidth, 0}); } else { if (spriteTab) { @@ -270,25 +241,21 @@ void FileTab::renderTab(tgui::BackendRenderTarget &target, spriteTabCopy.setSize({m_tabs[i].width, usableHeight}); target.drawSprite(states, spriteTabCopy); - } else // No texture was loaded - target.drawFilledRect( - states, {m_tabs[i].width, usableHeight}, - tgui::Color::applyOpacity(backgroundColor, m_opacityCached)); + } else // No texture was loaded + target.drawFilledRect(states, {m_tabs[i].width, usableHeight}, + tgui::Color::applyOpacity(backgroundColor, m_opacityCached)); // draw close button auto tabState = states; tabState.transform.translate( - {m_tabs[i].width - CLOSE_BUTTON_SIZE - MARGIN_LR, - (usableHeight - CLOSE_BUTTON_SIZE) / 2.f}); + {m_tabs[i].width - CLOSE_BUTTON_SIZE - MARGIN_LR, (usableHeight - CLOSE_BUTTON_SIZE) / 2.f}); close.setSize({CLOSE_BUTTON_SIZE, CLOSE_BUTTON_SIZE}); target.drawSprite(tabState, close); // Draw the borders between the tabs if ((borderWidth != 0) && (i < m_tabs.size())) { - target.drawBorders(states, Borders{borderWidth}, - {m_tabs[i].width, usableHeight}, - tgui::Color::applyOpacity(m_borderColorCached, - m_opacityCached)); + target.drawBorders(states, Borders{borderWidth}, {m_tabs[i].width, usableHeight}, + tgui::Color::applyOpacity(m_borderColorCached, m_opacityCached)); // target.drawFilledRect( // states, {borderWidth, usableHeight}, // tgui::Color::applyOpacity(m_borderColorCached, @@ -301,12 +268,10 @@ void FileTab::renderTab(tgui::BackendRenderTarget &target, // Highlight the borders of the selected and hovered tab when requested if (m_bordersCached != Borders{0}) { tgui::Color highlightColor; - if ((m_hoveringTab == static_cast(i)) && - m_borderColorHoverCached.isSet()) + if ((m_hoveringTab == static_cast(i)) && m_borderColorHoverCached.isSet()) highlightColor = m_borderColorHoverCached; if (m_selectedTab == static_cast(i)) { - if ((m_hoveringTab == static_cast(i)) && - m_selectedBorderColorHoverCached.isSet()) + if ((m_hoveringTab == static_cast(i)) && m_selectedBorderColorHoverCached.isSet()) highlightColor = m_selectedBorderColorHoverCached; else if (m_selectedBorderColorCached.isSet()) highlightColor = m_selectedBorderColorCached; @@ -315,36 +280,25 @@ void FileTab::renderTab(tgui::BackendRenderTarget &target, if (highlightColor.isSet()) { float leftBorderWidth = borderWidth; float rightBorderWidth = borderWidth; - if (i == 0) - leftBorderWidth = m_bordersCached.getLeft(); - if (i == m_tabs.size() - 1) - rightBorderWidth = m_bordersCached.getRight(); + if (i == 0) leftBorderWidth = m_bordersCached.getLeft(); + if (i == m_tabs.size() - 1) rightBorderWidth = m_bordersCached.getRight(); if ((m_selectedTab >= 0) && (m_hoveringTab >= 0) && (m_borderColorHoverCached.isSet() && - (m_selectedBorderColorCached.isSet() || - m_selectedBorderColorHoverCached.isSet()))) { - if ((m_selectedTab == static_cast(i - 1)) || - (m_hoveringTab == static_cast(i - 1))) + (m_selectedBorderColorCached.isSet() || m_selectedBorderColorHoverCached.isSet()))) { + if ((m_selectedTab == static_cast(i - 1)) || (m_hoveringTab == static_cast(i - 1))) leftBorderWidth /= 2; - else if ((m_selectedTab == static_cast(i + 1)) || - (m_hoveringTab == static_cast(i + 1))) + else if ((m_selectedTab == static_cast(i + 1)) || (m_hoveringTab == static_cast(i + 1))) rightBorderWidth /= 2; } RenderStates highlightStates = states; - if (i < m_tabs.size() - 1) - highlightStates.transform.translate({-borderWidth, 0}); - highlightStates.transform.translate( - {-m_tabs[i].width - leftBorderWidth, - -m_bordersCached.getTop()}); + if (i < m_tabs.size() - 1) highlightStates.transform.translate({-borderWidth, 0}); + highlightStates.transform.translate({-m_tabs[i].width - leftBorderWidth, -m_bordersCached.getTop()}); target.drawBorders( highlightStates, - {leftBorderWidth, m_bordersCached.getTop(), rightBorderWidth, - m_bordersCached.getBottom()}, - {m_tabs[i].width + leftBorderWidth + rightBorderWidth, - getSize().y}, - highlightColor); + {leftBorderWidth, m_bordersCached.getTop(), rightBorderWidth, m_bordersCached.getBottom()}, + {m_tabs[i].width + leftBorderWidth + rightBorderWidth, getSize().y}, highlightColor); } } @@ -352,30 +306,23 @@ void FileTab::renderTab(tgui::BackendRenderTarget &target, const float usableWidth = m_tabs[i].width - (2 * m_distanceToSideCached); const bool clippingRequired = (m_tabs[i].text.getSize().x > usableWidth); if (clippingRequired) - target.addClippingLayer(textStates, {{m_distanceToSideCached, 0}, - {usableWidth, usableHeight}}); + target.addClippingLayer(textStates, {{m_distanceToSideCached, 0}, {usableWidth, usableHeight}}); // Draw the text - textStates.transform.translate( - {m_distanceToSideCached + - ((usableWidth - m_tabs[i].text.getSize().x) / 2.f), - ((usableHeight - m_tabs[i].text.getSize().y) / 2.f)}); + textStates.transform.translate({m_distanceToSideCached + ((usableWidth - m_tabs[i].text.getSize().x) / 2.f), + ((usableHeight - m_tabs[i].text.getSize().y) / 2.f)}); target.drawText(textStates, m_tabs[i].text); - if (clippingRequired) - target.removeClippingLayer(); + if (clippingRequired) target.removeClippingLayer(); } -void FileTab::draw(tgui::BackendRenderTarget &target, - tgui::RenderStates states) const { - auto closeImagePath = - Editor::instance->getFs().getResourcePath("close.png"); +void FileTab::draw(tgui::BackendRenderTarget &target, tgui::RenderStates states) const { + auto closeImagePath = Editor::instance->getFs().getResourcePath("close.png"); tgui::Texture closeTexture(closeImagePath); Sprite close(closeTexture); const float borderWidth = (m_bordersCached.getLeftPlusRight()) / 2.f; - const bool roundedCorners = - (m_roundedBorderRadiusCached > 0) && !m_spriteTab.isSet(); + const bool roundedCorners = (m_roundedBorderRadiusCached > 0) && !m_spriteTab.isSet(); if (!roundedCorners) { // // Draw the borders around the tabs // if (m_bordersCached != Borders{0}) { @@ -396,31 +343,23 @@ void FileTab::draw(tgui::BackendRenderTarget &target, states.transform.translate({m_tabs[i].width, 0}); continue; } - renderTab(target, states, i, roundedCorners, borderWidth, usableHeight, - close); + renderTab(target, states, i, roundedCorners, borderWidth, usableHeight, close); } if (isDragging) { draggingState.transform.translate({deltaMousePos.x, 0}); - renderTab(target, draggingState, draggedTab, roundedCorners, - borderWidth, usableHeight, close); + renderTab(target, draggingState, draggedTab, roundedCorners, borderWidth, usableHeight, close); draggingState.transform.translate({-deltaMousePos.x, 0}); } } -tgui::Widget::Ptr FileTab::clone() const { - return std::make_shared(*this); -} +tgui::Widget::Ptr FileTab::clone() const { return std::make_shared(*this); } FileTabRenderer *FileTab::getSharedRenderer() { - return aurora::downcast( - tgui::Widget::getSharedRenderer()); + return aurora::downcast(tgui::Widget::getSharedRenderer()); } const FileTabRenderer *FileTab::getSharedRenderer() const { - return aurora::downcast( - tgui::Widget::getSharedRenderer()); + return aurora::downcast(tgui::Widget::getSharedRenderer()); } -FileTabRenderer *FileTab::getRenderer() { - return aurora::downcast(tgui::Widget::getRenderer()); -} +FileTabRenderer *FileTab::getRenderer() { return aurora::downcast(tgui::Widget::getRenderer()); } diff --git a/src/editor/widgets/frameEditor.cpp b/src/editor/widgets/frameEditor.cpp index a9c0f1cf..29222599 100644 --- a/src/editor/widgets/frameEditor.cpp +++ b/src/editor/widgets/frameEditor.cpp @@ -1,10 +1,12 @@ #include "widgets/frameEditor.hpp" -#include "TGUI/SubwidgetContainer.hpp" + +#include +#include + #include "TGUI/Widget.hpp" #include "TGUI/Widgets/Button.hpp" #include "TGUI/Widgets/ComboBox.hpp" #include "TGUI/Widgets/GrowHorizontalLayout.hpp" -#include "TGUI/Widgets/GrowVerticalLayout.hpp" #include "TGUI/Widgets/ToggleButton.hpp" #include "actor.hpp" #include "bindTranslation.hpp" @@ -13,16 +15,12 @@ #include "fileViews/actorFileView.hpp" #include "raylib.h" #include "services/translationService.hpp" -#include -#include constexpr int MAX_TOP_BAR_HEIGHT = 30; constexpr int MAX_ANI_BAR_HEIGHT = 50; -FrameEditor::FrameEditor(ActorFileView *fileView, const char *typeName, - bool initRenderer) - : tgui::ScrollablePanel(typeName, initRenderer), fileView(fileView), - actorView(fileView->getActorView()) {} +FrameEditor::FrameEditor(ActorFileView *fileView, const char *typeName, bool initRenderer) + : tgui::ScrollablePanel(typeName, initRenderer), fileView(fileView), actorView(fileView->getActorView()) {} void FrameEditor::onFrameChange(int currentFrame) {} @@ -41,14 +39,12 @@ void FrameEditor::init() { this->directionChooser = tgui::ComboBox::create(); - bindCustomTranslation( - directionChooser, [](tgui::ComboBox::Ptr box, TranslationService &ts) { - box->removeAllItems(); - for (int i = 0; i <= RPGPP_MAX_DIRECTION; i++) - box->addItem( - ts.getKey(TextFormat("screen.project.actorview.dir%d", i))); - box->setSelectedItemByIndex(0); - }); + bindTranslationWithCallback(directionChooser, [](tgui::ComboBox::Ptr box, TranslationService &ts) { + box->removeAllItems(); + for (int i = 0; i <= RPGPP_MAX_DIRECTION; i++) + box->addItem(ts.getKey(TextFormat("screen.project.actorview.dir%d", i))); + box->setSelectedItemByIndex(0); + }); directionChooser->onItemSelect.connect([this, &actor](const size_t &index) { this->changeFrameState(index); @@ -57,17 +53,15 @@ void FrameEditor::init() { frameLayout->remove(btn); } frameButtons.clear(); - for (int i = 0; i < actor->getAnimationCount(); i++) - this->addFrameButton(i); + for (int i = 0; i < actor->getAnimationCount(); i++) this->addFrameButton(i); }); topBarLayout->add(directionChooser); playPauseButton = tgui::ToggleButton::create(); - bindCustomTranslation( - playPauseButton, - [this](tgui::ToggleButton::Ptr button, TranslationService &ts) { + bindTranslationWithCallback( + playPauseButton, [this](tgui::ToggleButton::Ptr button, TranslationService &ts) { if (button->isDown()) { button->setText(ts.getKey("screen.project.actorview.pause")); } else { @@ -75,9 +69,8 @@ void FrameEditor::init() { } button->onToggle.disconnectAll(); button->onToggle.connect([&, button](const bool &checked) { - button->setText( - checked ? ts.getKey("screen.project.actorview.pause") - : ts.getKey("screen.project.actorview.play")); + button->setText(checked ? ts.getKey("screen.project.actorview.pause") + : ts.getKey("screen.project.actorview.play")); actorView->isPlaying = checked; }); }); @@ -85,22 +78,18 @@ void FrameEditor::init() { topBarLayout->add(playPauseButton); auto editingAtlasData = tgui::ToggleButton::create(); - bindTranslation( - editingAtlasData, "screen.project.actorview.edit_anim_data", - &tgui::ToggleButton::setText); + bindTranslation(editingAtlasData, "screen.project.actorview.edit_anim_data", + &tgui::ToggleButton::setText); editingAtlasData->setSize({200, "100%"}); - editingAtlasData->onToggle.connect( - [this](const bool isChecked) { actorView->editData = isChecked; }); + editingAtlasData->onToggle.connect([this](const bool isChecked) { actorView->editData = isChecked; }); topBarLayout->add(editingAtlasData); auto delFrame = tgui::Button::create(); - bindTranslation(delFrame, "screen.project.actorview.delete", - &tgui::Button::setText); + bindTranslation(delFrame, "screen.project.actorview.delete", &tgui::Button::setText); delFrame->onPress.connect([&] { if (actor->getAnimationCount() > 1) { // Remove the last frame button. - actor->removeAnimationFrame(actor->getAnimationDirection(), - actor->getCurrentFrame()); + actor->removeAnimationFrame(actor->getAnimationDirection(), actor->getCurrentFrame()); const auto &lastButton = this->frameButtons.back(); @@ -117,8 +106,7 @@ void FrameEditor::init() { this->frameLayout = tgui::GrowHorizontalLayout::create(); frameLayout->getRenderer()->setSpaceBetweenWidgets(3.0f); - for (int i = 0; i < actor->getAnimationCount(); i++) - this->addFrameButton(i); + for (int i = 0; i < actor->getAnimationCount(); i++) this->addFrameButton(i); auto encaserLayout = tgui::GrowHorizontalLayout::create(); encaserLayout->add(frameLayout); @@ -139,20 +127,15 @@ void FrameEditor::init() { void FrameEditor::addFrameButton(int index) { const auto &actor = actorView->actor; auto frameButton = FrameButton::create(index, actor); - frameButton->onFrameChange.connect( - [&](const int &index) { actor->setAnimationFrame(index); }); + frameButton->onFrameChange.connect([&](const int &index) { actor->setAnimationFrame(index); }); this->frameButtons.push_back(frameButton); this->frameLayout->add(frameButton); } -FrameEditor::Ptr FrameEditor::create(ActorFileView *fileView) { - return std::make_shared(fileView); -} +FrameEditor::Ptr FrameEditor::create(ActorFileView *fileView) { return std::make_shared(fileView); } -tgui::Widget::Ptr FrameEditor::clone() const { - return std::make_shared(*this); -} +tgui::Widget::Ptr FrameEditor::clone() const { return std::make_shared(*this); } void FrameEditor::changeFrameState(int index) { const auto &actor = actorView->actor; diff --git a/src/editor/widgets/hotkeyModifier.cpp b/src/editor/widgets/hotkeyModifier.cpp index 801fa6fc..0f819659 100644 --- a/src/editor/widgets/hotkeyModifier.cpp +++ b/src/editor/widgets/hotkeyModifier.cpp @@ -1,414 +1,415 @@ +#include +#include + #include "TGUI/SubwidgetContainer.hpp" #include "TGUI/Widgets/Button.hpp" #include "bindTranslation.hpp" #include "editor.hpp" #include "raylib.h" #include "services/translationService.hpp" -#include -#include // this is the most unholy shit i've wrote const KeyboardKey tguiToRaylibKey(tguiKey k) { switch (k) { - case tguiKey::A: - return KEY_A; - case tguiKey::B: - return KEY_B; - case tguiKey::C: - return KEY_C; - case tguiKey::D: - return KEY_D; - case tguiKey::E: - return KEY_E; - case tguiKey::F: - return KEY_F; - case tguiKey::G: - return KEY_G; - case tguiKey::H: - return KEY_H; - case tguiKey::I: - return KEY_I; - case tguiKey::J: - return KEY_J; - case tguiKey::K: - return KEY_K; - case tguiKey::L: - return KEY_L; - case tguiKey::M: - return KEY_M; - case tguiKey::N: - return KEY_N; - case tguiKey::O: - return KEY_O; - case tguiKey::P: - return KEY_P; - case tguiKey::Q: - return KEY_Q; - case tguiKey::R: - return KEY_R; - case tguiKey::S: - return KEY_S; - case tguiKey::T: - return KEY_T; - case tguiKey::U: - return KEY_U; - case tguiKey::V: - return KEY_V; - case tguiKey::W: - return KEY_W; - case tguiKey::X: - return KEY_X; - case tguiKey::Y: - return KEY_Y; - case tguiKey::Z: - return KEY_Z; - case tguiKey::Num0: - return KEY_ZERO; - case tguiKey::Num1: - return KEY_ONE; - case tguiKey::Num2: - return KEY_TWO; - case tguiKey::Num3: - return KEY_THREE; - case tguiKey::Num4: - return KEY_FOUR; - case tguiKey::Num5: - return KEY_FIVE; - case tguiKey::Num6: - return KEY_SIX; - case tguiKey::Num7: - return KEY_SEVEN; - case tguiKey::Num8: - return KEY_EIGHT; - case tguiKey::Num9: - return KEY_NINE; - case tguiKey::Escape: - return KEY_ESCAPE; - case tguiKey::LControl: - return KEY_LEFT_CONTROL; - case tguiKey::LShift: - return KEY_LEFT_SHIFT; - case tguiKey::LAlt: - return KEY_LEFT_ALT; - case tguiKey::LSystem: - return KEY_LEFT_SUPER; - case tguiKey::RControl: - return KEY_RIGHT_CONTROL; - case tguiKey::RShift: - return KEY_RIGHT_SHIFT; - case tguiKey::RAlt: - return KEY_RIGHT_ALT; - case tguiKey::RSystem: - return KEY_RIGHT_SUPER; - case tguiKey::Menu: - return KEY_KB_MENU; - case tguiKey::LBracket: - return KEY_LEFT_BRACKET; - case tguiKey::RBracket: - return KEY_RIGHT_BRACKET; - case tguiKey::Semicolon: - return KEY_SEMICOLON; - case tguiKey::Comma: - return KEY_COMMA; - case tguiKey::Period: - return KEY_PERIOD; - case tguiKey::Quote: - return KEY_APOSTROPHE; - case tguiKey::Slash: - return KEY_SLASH; - case tguiKey::Backslash: - return KEY_BACKSLASH; - case tguiKey::Equal: - return KEY_EQUAL; - case tguiKey::Minus: - return KEY_MINUS; - case tguiKey::Space: - return KEY_SPACE; - case tguiKey::Enter: - return KEY_ENTER; - case tguiKey::Backspace: - return KEY_BACKSPACE; - case tguiKey::Tab: - return KEY_TAB; - case tguiKey::PageUp: - return KEY_PAGE_UP; - case tguiKey::PageDown: - return KEY_PAGE_DOWN; - case tguiKey::End: - return KEY_END; - case tguiKey::Home: - return KEY_HOME; - case tguiKey::Insert: - return KEY_INSERT; - case tguiKey::Delete: - return KEY_DELETE; - case tguiKey::Add: - return KEY_KP_ADD; - case tguiKey::Subtract: - return KEY_KP_SUBTRACT; - case tguiKey::Multiply: - return KEY_KP_MULTIPLY; - case tguiKey::Divide: - return KEY_KP_DIVIDE; - case tguiKey::Left: - return KEY_LEFT; - case tguiKey::Right: - return KEY_RIGHT; - case tguiKey::Up: - return KEY_UP; - case tguiKey::Down: - return KEY_DOWN; - case tguiKey::Numpad0: - return KEY_KP_0; - case tguiKey::Numpad1: - return KEY_KP_1; - case tguiKey::Numpad2: - return KEY_KP_2; - case tguiKey::Numpad3: - return KEY_KP_3; - case tguiKey::Numpad4: - return KEY_KP_4; - case tguiKey::Numpad5: - return KEY_KP_5; - case tguiKey::Numpad6: - return KEY_KP_6; - case tguiKey::Numpad7: - return KEY_KP_7; - case tguiKey::Numpad8: - return KEY_KP_8; - case tguiKey::Numpad9: - return KEY_KP_9; - case tguiKey::F1: - return KEY_F1; - case tguiKey::F2: - return KEY_F2; - case tguiKey::F3: - return KEY_F3; - case tguiKey::F4: - return KEY_F4; - case tguiKey::F5: - return KEY_F5; - case tguiKey::F6: - return KEY_F6; - case tguiKey::F7: - return KEY_F7; - case tguiKey::F8: - return KEY_F8; - case tguiKey::F9: - return KEY_F9; - case tguiKey::F10: - return KEY_F10; - case tguiKey::F11: - return KEY_F11; - case tguiKey::F12: - return KEY_F12; - case tguiKey::Tilde: - case tguiKey::F13: - case tguiKey::F14: - case tguiKey::F15: - case tguiKey::Pause: - case tguiKey::Unknown: - return KEY_NULL; + case tguiKey::A: + return KEY_A; + case tguiKey::B: + return KEY_B; + case tguiKey::C: + return KEY_C; + case tguiKey::D: + return KEY_D; + case tguiKey::E: + return KEY_E; + case tguiKey::F: + return KEY_F; + case tguiKey::G: + return KEY_G; + case tguiKey::H: + return KEY_H; + case tguiKey::I: + return KEY_I; + case tguiKey::J: + return KEY_J; + case tguiKey::K: + return KEY_K; + case tguiKey::L: + return KEY_L; + case tguiKey::M: + return KEY_M; + case tguiKey::N: + return KEY_N; + case tguiKey::O: + return KEY_O; + case tguiKey::P: + return KEY_P; + case tguiKey::Q: + return KEY_Q; + case tguiKey::R: + return KEY_R; + case tguiKey::S: + return KEY_S; + case tguiKey::T: + return KEY_T; + case tguiKey::U: + return KEY_U; + case tguiKey::V: + return KEY_V; + case tguiKey::W: + return KEY_W; + case tguiKey::X: + return KEY_X; + case tguiKey::Y: + return KEY_Y; + case tguiKey::Z: + return KEY_Z; + case tguiKey::Num0: + return KEY_ZERO; + case tguiKey::Num1: + return KEY_ONE; + case tguiKey::Num2: + return KEY_TWO; + case tguiKey::Num3: + return KEY_THREE; + case tguiKey::Num4: + return KEY_FOUR; + case tguiKey::Num5: + return KEY_FIVE; + case tguiKey::Num6: + return KEY_SIX; + case tguiKey::Num7: + return KEY_SEVEN; + case tguiKey::Num8: + return KEY_EIGHT; + case tguiKey::Num9: + return KEY_NINE; + case tguiKey::Escape: + return KEY_ESCAPE; + case tguiKey::LControl: + return KEY_LEFT_CONTROL; + case tguiKey::LShift: + return KEY_LEFT_SHIFT; + case tguiKey::LAlt: + return KEY_LEFT_ALT; + case tguiKey::LSystem: + return KEY_LEFT_SUPER; + case tguiKey::RControl: + return KEY_RIGHT_CONTROL; + case tguiKey::RShift: + return KEY_RIGHT_SHIFT; + case tguiKey::RAlt: + return KEY_RIGHT_ALT; + case tguiKey::RSystem: + return KEY_RIGHT_SUPER; + case tguiKey::Menu: + return KEY_KB_MENU; + case tguiKey::LBracket: + return KEY_LEFT_BRACKET; + case tguiKey::RBracket: + return KEY_RIGHT_BRACKET; + case tguiKey::Semicolon: + return KEY_SEMICOLON; + case tguiKey::Comma: + return KEY_COMMA; + case tguiKey::Period: + return KEY_PERIOD; + case tguiKey::Quote: + return KEY_APOSTROPHE; + case tguiKey::Slash: + return KEY_SLASH; + case tguiKey::Backslash: + return KEY_BACKSLASH; + case tguiKey::Equal: + return KEY_EQUAL; + case tguiKey::Minus: + return KEY_MINUS; + case tguiKey::Space: + return KEY_SPACE; + case tguiKey::Enter: + return KEY_ENTER; + case tguiKey::Backspace: + return KEY_BACKSPACE; + case tguiKey::Tab: + return KEY_TAB; + case tguiKey::PageUp: + return KEY_PAGE_UP; + case tguiKey::PageDown: + return KEY_PAGE_DOWN; + case tguiKey::End: + return KEY_END; + case tguiKey::Home: + return KEY_HOME; + case tguiKey::Insert: + return KEY_INSERT; + case tguiKey::Delete: + return KEY_DELETE; + case tguiKey::Add: + return KEY_KP_ADD; + case tguiKey::Subtract: + return KEY_KP_SUBTRACT; + case tguiKey::Multiply: + return KEY_KP_MULTIPLY; + case tguiKey::Divide: + return KEY_KP_DIVIDE; + case tguiKey::Left: + return KEY_LEFT; + case tguiKey::Right: + return KEY_RIGHT; + case tguiKey::Up: + return KEY_UP; + case tguiKey::Down: + return KEY_DOWN; + case tguiKey::Numpad0: + return KEY_KP_0; + case tguiKey::Numpad1: + return KEY_KP_1; + case tguiKey::Numpad2: + return KEY_KP_2; + case tguiKey::Numpad3: + return KEY_KP_3; + case tguiKey::Numpad4: + return KEY_KP_4; + case tguiKey::Numpad5: + return KEY_KP_5; + case tguiKey::Numpad6: + return KEY_KP_6; + case tguiKey::Numpad7: + return KEY_KP_7; + case tguiKey::Numpad8: + return KEY_KP_8; + case tguiKey::Numpad9: + return KEY_KP_9; + case tguiKey::F1: + return KEY_F1; + case tguiKey::F2: + return KEY_F2; + case tguiKey::F3: + return KEY_F3; + case tguiKey::F4: + return KEY_F4; + case tguiKey::F5: + return KEY_F5; + case tguiKey::F6: + return KEY_F6; + case tguiKey::F7: + return KEY_F7; + case tguiKey::F8: + return KEY_F8; + case tguiKey::F9: + return KEY_F9; + case tguiKey::F10: + return KEY_F10; + case tguiKey::F11: + return KEY_F11; + case tguiKey::F12: + return KEY_F12; + case tguiKey::Tilde: + case tguiKey::F13: + case tguiKey::F14: + case tguiKey::F15: + case tguiKey::Pause: + case tguiKey::Unknown: + return KEY_NULL; } return KEY_NULL; } const std::string keyboardKeyToName(KeyboardKey k) { switch (k) { - case KEY_NULL: - return "Unknown"; - case KEY_APOSTROPHE: - return "'"; - case KEY_COMMA: - return ","; - case KEY_MINUS: - return "-"; - case KEY_PERIOD: - return "."; - case KEY_SLASH: - return "/"; - case KEY_ZERO: - return "0"; - case KEY_ONE: - return "1"; - case KEY_TWO: - return "2"; - case KEY_THREE: - return "3"; - case KEY_FOUR: - return "4"; - case KEY_FIVE: - return "5"; - case KEY_SIX: - return "6"; - case KEY_SEVEN: - return "7"; - case KEY_EIGHT: - return "8"; - case KEY_NINE: - return "9"; - case KEY_SEMICOLON: - return ";"; - case KEY_EQUAL: - return "="; - case KEY_A: - return "A"; - case KEY_B: - return "B"; - case KEY_C: - return "C"; - case KEY_D: - return "D"; - case KEY_E: - return "E"; - case KEY_F: - return "F"; - case KEY_G: - return "G"; - case KEY_H: - return "H"; - case KEY_I: - return "I"; - case KEY_J: - return "J"; - case KEY_K: - return "K"; - case KEY_L: - return "L"; - case KEY_M: - return "M"; - case KEY_N: - return "N"; - case KEY_O: - return "O"; - case KEY_P: - return "P"; - case KEY_Q: - return "Q"; - case KEY_R: - return "R"; - case KEY_S: - return "S"; - case KEY_T: - return "T"; - case KEY_U: - return "U"; - case KEY_V: - return "V"; - case KEY_W: - return "W"; - case KEY_X: - return "X"; - case KEY_Y: - return "Y"; - case KEY_Z: - return "Z"; - case KEY_LEFT_BRACKET: - return "["; - case KEY_BACKSLASH: - return "\\"; - case KEY_RIGHT_BRACKET: - return "]"; - case KEY_SPACE: - return "Space"; - case KEY_ESCAPE: - return "Esc"; - case KEY_ENTER: - return "Enter"; - case KEY_TAB: - return "Tab"; - case KEY_BACKSPACE: - return "Backspace"; - case KEY_INSERT: - return "Ins"; - case KEY_DELETE: - return "Del"; - case KEY_RIGHT: - return "Right"; - case KEY_LEFT: - return "Left"; - case KEY_DOWN: - return "Down"; - case KEY_UP: - return "Up"; - case KEY_PAGE_UP: - return "PgUp"; - case KEY_PAGE_DOWN: - return "PgDn"; - case KEY_HOME: - return "Home"; - case KEY_END: - return "End"; - case KEY_F1: - return "F1"; - case KEY_F2: - return "F2"; - case KEY_F3: - return "F3"; - case KEY_F4: - return "F4"; - case KEY_F5: - return "F5"; - case KEY_F6: - return "F6"; - case KEY_F7: - return "F7"; - case KEY_F8: - return "F8"; - case KEY_F9: - return "F9"; - case KEY_F10: - return "F10"; - case KEY_F11: - return "F11"; - case KEY_F12: - return "F12"; - case KEY_LEFT_SHIFT: - return "Shift"; - case KEY_LEFT_CONTROL: - return "Control"; - case KEY_LEFT_ALT: - return "Alt"; - case KEY_LEFT_SUPER: - return "Super"; - case KEY_RIGHT_SHIFT: - return "RightShift"; - case KEY_RIGHT_CONTROL: - return "RightControl"; - case KEY_RIGHT_ALT: - return "RightAlt"; - case KEY_RIGHT_SUPER: - return "RightSuper"; - case KEY_KB_MENU: - return "KBMenu"; - case KEY_KP_0: - return "Keypad0"; - case KEY_KP_1: - return "Keypad1"; - case KEY_KP_2: - return "Keypad2"; - case KEY_KP_3: - return "Keypad3"; - case KEY_KP_4: - return "Keypad4"; - case KEY_KP_5: - return "Keypad5"; - case KEY_KP_6: - return "Keypad6"; - case KEY_KP_7: - return "Keypad7"; - case KEY_KP_8: - return "Keypad8"; - case KEY_KP_9: - return "Keypad9"; - case KEY_KP_DIVIDE: - return "Keypad /"; - case KEY_KP_MULTIPLY: - return "Keypad *"; - case KEY_KP_SUBTRACT: - return "Keypad -"; - case KEY_KP_ADD: - return "Keypad +"; - default: - return "Unknown"; + case KEY_NULL: + return "Unknown"; + case KEY_APOSTROPHE: + return "'"; + case KEY_COMMA: + return ","; + case KEY_MINUS: + return "-"; + case KEY_PERIOD: + return "."; + case KEY_SLASH: + return "/"; + case KEY_ZERO: + return "0"; + case KEY_ONE: + return "1"; + case KEY_TWO: + return "2"; + case KEY_THREE: + return "3"; + case KEY_FOUR: + return "4"; + case KEY_FIVE: + return "5"; + case KEY_SIX: + return "6"; + case KEY_SEVEN: + return "7"; + case KEY_EIGHT: + return "8"; + case KEY_NINE: + return "9"; + case KEY_SEMICOLON: + return ";"; + case KEY_EQUAL: + return "="; + case KEY_A: + return "A"; + case KEY_B: + return "B"; + case KEY_C: + return "C"; + case KEY_D: + return "D"; + case KEY_E: + return "E"; + case KEY_F: + return "F"; + case KEY_G: + return "G"; + case KEY_H: + return "H"; + case KEY_I: + return "I"; + case KEY_J: + return "J"; + case KEY_K: + return "K"; + case KEY_L: + return "L"; + case KEY_M: + return "M"; + case KEY_N: + return "N"; + case KEY_O: + return "O"; + case KEY_P: + return "P"; + case KEY_Q: + return "Q"; + case KEY_R: + return "R"; + case KEY_S: + return "S"; + case KEY_T: + return "T"; + case KEY_U: + return "U"; + case KEY_V: + return "V"; + case KEY_W: + return "W"; + case KEY_X: + return "X"; + case KEY_Y: + return "Y"; + case KEY_Z: + return "Z"; + case KEY_LEFT_BRACKET: + return "["; + case KEY_BACKSLASH: + return "\\"; + case KEY_RIGHT_BRACKET: + return "]"; + case KEY_SPACE: + return "Space"; + case KEY_ESCAPE: + return "Esc"; + case KEY_ENTER: + return "Enter"; + case KEY_TAB: + return "Tab"; + case KEY_BACKSPACE: + return "Backspace"; + case KEY_INSERT: + return "Ins"; + case KEY_DELETE: + return "Del"; + case KEY_RIGHT: + return "Right"; + case KEY_LEFT: + return "Left"; + case KEY_DOWN: + return "Down"; + case KEY_UP: + return "Up"; + case KEY_PAGE_UP: + return "PgUp"; + case KEY_PAGE_DOWN: + return "PgDn"; + case KEY_HOME: + return "Home"; + case KEY_END: + return "End"; + case KEY_F1: + return "F1"; + case KEY_F2: + return "F2"; + case KEY_F3: + return "F3"; + case KEY_F4: + return "F4"; + case KEY_F5: + return "F5"; + case KEY_F6: + return "F6"; + case KEY_F7: + return "F7"; + case KEY_F8: + return "F8"; + case KEY_F9: + return "F9"; + case KEY_F10: + return "F10"; + case KEY_F11: + return "F11"; + case KEY_F12: + return "F12"; + case KEY_LEFT_SHIFT: + return "Shift"; + case KEY_LEFT_CONTROL: + return "Control"; + case KEY_LEFT_ALT: + return "Alt"; + case KEY_LEFT_SUPER: + return "Super"; + case KEY_RIGHT_SHIFT: + return "RightShift"; + case KEY_RIGHT_CONTROL: + return "RightControl"; + case KEY_RIGHT_ALT: + return "RightAlt"; + case KEY_RIGHT_SUPER: + return "RightSuper"; + case KEY_KB_MENU: + return "KBMenu"; + case KEY_KP_0: + return "Keypad0"; + case KEY_KP_1: + return "Keypad1"; + case KEY_KP_2: + return "Keypad2"; + case KEY_KP_3: + return "Keypad3"; + case KEY_KP_4: + return "Keypad4"; + case KEY_KP_5: + return "Keypad5"; + case KEY_KP_6: + return "Keypad6"; + case KEY_KP_7: + return "Keypad7"; + case KEY_KP_8: + return "Keypad8"; + case KEY_KP_9: + return "Keypad9"; + case KEY_KP_DIVIDE: + return "Keypad /"; + case KEY_KP_MULTIPLY: + return "Keypad *"; + case KEY_KP_SUBTRACT: + return "Keypad -"; + case KEY_KP_ADD: + return "Keypad +"; + default: + return "Unknown"; } } @@ -420,16 +421,13 @@ HotkeyModifier::HotkeyModifier(const char *typeName, bool initRenderer) TranslationService &ts = Editor::instance->getTranslations(); if (modifingState == State::DEFAULT) { modifingState = State::START_EDITING; - this->button->setText( - ts.getKey("widget.hotkey_modifier.listening")); + this->button->setText(ts.getKey("widget.hotkey_modifier.listening")); } }); m_container->add(this->button); } -HotkeyModifier::Ptr HotkeyModifier::create() { - return std::make_shared(); -} +HotkeyModifier::Ptr HotkeyModifier::create() { return std::make_shared(); } HotkeyModifier::Ptr HotkeyModifier::copy(HotkeyModifier::ConstPtr widget) { if (widget) @@ -438,15 +436,11 @@ HotkeyModifier::Ptr HotkeyModifier::copy(HotkeyModifier::ConstPtr widget) { return nullptr; } -tgui::Widget::Ptr HotkeyModifier::clone() const { - return std::make_shared(*this); -} +tgui::Widget::Ptr HotkeyModifier::clone() const { return std::make_shared(*this); } -void HotkeyModifier::setKey(const std::string &id, KeyboardKey key, - bool isShift, bool isCtrl, bool isAlt, bool isSuper, +void HotkeyModifier::setKey(const std::string &id, KeyboardKey key, bool isShift, bool isCtrl, bool isAlt, bool isSuper, bool override) { - if (modifingState == State::DEFAULT && !override) - return; + if (modifingState == State::DEFAULT && !override) return; keys.clear(); if (isSuper) { keys.push_back(KEY_LEFT_SUPER); @@ -463,8 +457,7 @@ void HotkeyModifier::setKey(const std::string &id, KeyboardKey key, keys.push_back(key); std::string label{}; for (auto i = keys.begin(); i != keys.end(); ++i) { - if (i != keys.begin()) - label += "+"; + if (i != keys.begin()) label += "+"; label += keyboardKeyToName(*i); } this->button->setText(label); @@ -475,8 +468,7 @@ void HotkeyModifier::setKey(const std::string &id, KeyboardKey key, void HotkeyModifier::keyPressed(const tgui::Event::KeyEvent &event) { tgui::SubwidgetContainer::keyPressed(event); - setKey(this->id, tguiToRaylibKey(event.code), event.shift, event.control, - event.alt, event.system); + setKey(this->id, tguiToRaylibKey(event.code), event.shift, event.control, event.alt, event.system); modifingState = State::DEFAULT; onChange.emit(this, this->id, hk); } diff --git a/src/editor/widgets/newProjectWindow.cpp b/src/editor/widgets/newProjectWindow.cpp index dad97f20..d3d33e16 100644 --- a/src/editor/widgets/newProjectWindow.cpp +++ b/src/editor/widgets/newProjectWindow.cpp @@ -1,8 +1,13 @@ #include "widgets/newProjectWindow.hpp" + +#include + #include "TGUI/String.hpp" #include "TGUI/Widgets/Button.hpp" +#include "TGUI/Widgets/CheckBox.hpp" #include "TGUI/Widgets/ChildWindow.hpp" #include "TGUI/Widgets/EditBox.hpp" +#include "TGUI/Widgets/Group.hpp" #include "TGUI/Widgets/GrowVerticalLayout.hpp" #include "TGUI/Widgets/Label.hpp" #include "TGUI/Widgets/Panel.hpp" @@ -10,16 +15,14 @@ #include "editor.hpp" #include "services/translationService.hpp" #include "widgets/fileChooser.hpp" -#include NewProjectWindow::NewProjectWindow(const char *typeName, bool initRenderer) {} void NewProjectWindow::init(tgui::Gui *gui) { TranslationService &tService = Editor::instance->getTranslations(); window = tgui::ChildWindow::create(); - bindTranslation(window, "dialog.new_project.title", - &tgui::ChildWindow::setTitle); - window->setSize(320, 220); + bindTranslation(window, "dialog.new_project.title", &tgui::ChildWindow::setTitle); + window->setSize(320, 250); auto panel = tgui::Panel::create(); panel->getRenderer()->setPadding({PADDING}); @@ -29,8 +32,7 @@ void NewProjectWindow::init(tgui::Gui *gui) { panel->add(vertLayout); auto titleLabel = tgui::Label::create(); - bindTranslation(titleLabel, "dialog.new_project.name", - &tgui::Label::setText); + bindTranslation(titleLabel, "dialog.new_project.name", &tgui::Label::setText); vertLayout->add(titleLabel); titleField = tgui::EditBox::create(); @@ -42,29 +44,36 @@ void NewProjectWindow::init(tgui::Gui *gui) { vertLayout->add(gap); fileLabel = tgui::Label::create(); - bindTranslation(fileLabel, "dialog.new_project.folder", - &tgui::Label::setText); + bindTranslation(fileLabel, "dialog.new_project.folder", &tgui::Label::setText); vertLayout->add(fileLabel); fileField = FileChooser::create(); fileField->setSize({"100%", FIELD_H}); vertLayout->add(fileField); + auto gap2 = tgui::Label::copy(gap); + + vertLayout->add(gap2); + + auto makeDirPanel = tgui::Group::create({"100%", FIELD_H}); + vertLayout->add(makeDirPanel); + + makeDirCheck = tgui::CheckBox::create(); + makeDirCheck->setSize({FIELD_H, FIELD_H}); + makeDirCheck->setText("Make Directory?"); + makeDirPanel->add(makeDirCheck); + confirmButton = tgui::Button::create(); - bindTranslation(confirmButton, "dialog.new_project.confirm", - &tgui::Button::setText); + bindTranslation(confirmButton, "dialog.new_project.confirm", &tgui::Button::setText); confirmButton->setSize(BUTTON_W, BUTTON_H); - confirmButton->setPosition(tgui::Layout("100%") - BUTTON_W - PADDING, - tgui::Layout("100%") - BUTTON_H - PADDING); + confirmButton->setPosition(tgui::Layout("100%") - BUTTON_W - PADDING, tgui::Layout("100%") - BUTTON_H - PADDING); window->add(confirmButton); cancelButton = tgui::Button::create(); - bindTranslation(cancelButton, "dialog.new_project.cancel", - &tgui::Button::setText); + bindTranslation(cancelButton, "dialog.new_project.cancel", &tgui::Button::setText); cancelButton->setSize(BUTTON_W, BUTTON_H); - cancelButton->setPosition(tgui::bindLeft(confirmButton) - BUTTON_W - - PADDING, + cancelButton->setPosition(tgui::bindLeft(confirmButton) - BUTTON_W - PADDING, tgui::Layout("100%") - BUTTON_H - PADDING); cancelButton->onPress([this] { window->close(); }); @@ -73,9 +82,7 @@ void NewProjectWindow::init(tgui::Gui *gui) { gui->add(window); } -NewProjectWindow::Ptr NewProjectWindow::create() { - return std::make_shared(); -} +NewProjectWindow::Ptr NewProjectWindow::create() { return std::make_shared(); } NewProjectWindow::Ptr NewProjectWindow::create(const tgui::String &title) { auto ptr = std::make_shared(); @@ -83,20 +90,12 @@ NewProjectWindow::Ptr NewProjectWindow::create(const tgui::String &title) { return ptr; } -void NewProjectWindow::setFieldTitle(const tgui::String &title) { - titleField->setDefaultText(title); -} +void NewProjectWindow::setFieldTitle(const tgui::String &title) { titleField->setDefaultText(title); } -void NewProjectWindow::setFileFieldTitle(const tgui::String &title) { - fileField->chosenPathLabel->setText(title); -} +void NewProjectWindow::setFileFieldTitle(const tgui::String &title) { fileField->chosenPathLabel->setText(title); } -void NewProjectWindow::setPathFilters( - std::vector>> - pathFilters) { +void NewProjectWindow::setPathFilters(std::vector>> pathFilters) { fileField->pathFilters = pathFilters; } -void NewProjectWindow::updateSize(const tgui::Layout2d &size) { - window->setSize(size.x, size.y); -} +void NewProjectWindow::updateSize(const tgui::Layout2d &size) { window->setSize(size.x, size.y); } diff --git a/src/editor/widgets/propertiesBox.cpp b/src/editor/widgets/propertiesBox.cpp index 34f15c7b..d372e955 100644 --- a/src/editor/widgets/propertiesBox.cpp +++ b/src/editor/widgets/propertiesBox.cpp @@ -1,4 +1,10 @@ #include "widgets/propertiesBox.hpp" + +#include + +#include +#include + #include "TGUI/String.hpp" #include "TGUI/Widget.hpp" #include "TGUI/Widgets/Button.hpp" @@ -6,30 +12,33 @@ #include "TGUI/Widgets/GrowVerticalLayout.hpp" #include "TGUI/Widgets/Label.hpp" #include "TGUI/Widgets/SpinControl.hpp" +#include "childWindows/editPropWindow.hpp" +#include "childWindows/newPropWindow.hpp" +#include "editor.hpp" #include "widgets/propertyFields/boolField.hpp" #include "widgets/propertyFields/fieldConfig.hpp" #include "widgets/propertyFields/fileField.hpp" #include "widgets/propertyFields/intField.hpp" +#include "widgets/propertyFields/interPropField.hpp" #include "widgets/propertyFields/rectangleField.hpp" #include "widgets/propertyFields/selectField.hpp" #include "widgets/propertyFields/textField.hpp" -#include -#include -#include -PropertiesBox::PropertiesBox(const char *typeName, bool initRenderer) - : tgui::ChildWindow(typeName, initRenderer) { +PropertiesBox::PropertiesBox(const char *typeName, bool initRenderer) : tgui::ChildWindow(typeName, initRenderer) { this->setTitle("Props"); this->setTitleButtons(tgui::ChildWindow::TitleButton::None); + auto vertLayout = tgui::GrowVerticalLayout::create(); vertLayout->getRenderer()->setSpaceBetweenWidgets(GAP); + + newPropButton = tgui::Button::create("New Prop.."); + newPropButton->setSize("100%", 24); + add(vertLayout); this->layout = vertLayout; } -PropertiesBox::Ptr PropertiesBox::create() { - return std::make_shared(); -} +PropertiesBox::Ptr PropertiesBox::create() { return std::make_shared(); } PropertiesBox::Ptr PropertiesBox::copy(PropertiesBox::ConstPtr widget) { if (widget) { @@ -39,79 +48,134 @@ PropertiesBox::Ptr PropertiesBox::copy(PropertiesBox::ConstPtr widget) { } } -tgui::Widget::Ptr PropertiesBox::clone() const { - return std::make_shared(*this); -} +tgui::Widget::Ptr PropertiesBox::clone() const { return std::make_shared(*this); } -void PropertiesBox::draw(tgui::BackendRenderTarget &target, - tgui::RenderStates states) const { +void PropertiesBox::draw(tgui::BackendRenderTarget &target, tgui::RenderStates states) const { tgui::ChildWindow::draw(target, states); } -void PropertiesBox::addPropsJson(nlohmann::json &j) { - for (auto item : j.items()) { - printf("%s \n", item.key().c_str()); - if (item.value().is_string()) { - printf("%s \n", item.value().get().c_str()); - - auto textField = TextField::create(); - textField->label->setText(item.key()); - textField->value->setText(item.value().get()); - textField->value->onTextChange( - [&j, item](const tgui::String &text) { +void PropertiesBox::addPropsJson(nlohmann::json &j, bool clear, bool editable) { + if (clear) { + layout->removeAllWidgets(); + } + + if (editable) { + if (clear) { + layout->add(newPropButton); + } + + // configure the 'New Prop' button + // newPropButton->setVisible(true); + layout->add(newPropButton); + newPropButton->onClick.disconnectAll(); + newPropButton->onClick([this] { + auto windowPtr = Editor::instance->getGui().getChildWindowSubService()->getWindow("new_prop"); + auto newPropWindow = static_cast(windowPtr); + + if (interactable != nullptr) { + newPropWindow->box = this; + newPropWindow->interactable = interactable; + } + + Editor::instance->getGui().getChildWindowSubService()->openWindow("new_prop"); + }); + + auto windowPtr = Editor::instance->getGui().getChildWindowSubService()->getWindow("edit_prop"); + auto editPropWindow = static_cast(windowPtr); + + // add fields for the props + for (auto item : j.items()) { + auto field = InterPropField::create(); + field->label->setText(item.key()); + field->value->onPress([this, item, editPropWindow] { + if (interactable != nullptr) { + editPropWindow->propName = item.key(); + editPropWindow->box = this; + editPropWindow->interactable = interactable; + + editPropWindow->nameLabel->setText(item.key()); + + editPropWindow->open(); + } + }); + + if (item.value().is_string()) { + field->value->setText("string"); + } + if (item.value().is_number()) { + field->value->setText("integer"); + } + if (item.value().is_boolean()) { + field->value->setText("boolean"); + } + if (item.value().is_object()) { + if (item.value().contains("propType")) { + std::string propType = item.value().at("propType"); + + if (propType == "dialogue") { + field->value->setText("dialogue"); + } + } + } + + addInterPropField(field); + } + } else { + for (auto item : j.items()) { + printf("%s \n", item.key().c_str()); + if (item.value().is_string()) { + printf("%s \n", item.value().get().c_str()); + + auto textField = TextField::create(); + textField->label->setText(item.key()); + textField->value->setText(item.value().get()); + textField->value->onTextChange([&j, item](const tgui::String &text) { std::string st = text.toStdString(); j.at(item.key()) = st; }); - addTextField(textField); - } - if (item.value().is_number()) { - auto intField = IntField::create(); - intField->label->setText(item.key()); - intField->value->setValue(item.value().get()); - intField->value->onValueChange( - [&j, item](float value) { j.at(item.key()) = value; }); - addIntField(intField); - } - if (item.value().is_boolean()) { - auto boolField = BoolField::create(); - boolField->label->setText(item.key()); - boolField->value->setChecked(item.value().get()); - boolField->value->onChange( - [&j, item](bool checked) { j.at(item.key()) = checked; }); - addBooleanField(boolField); - } - if (item.value().is_object()) { - if (item.value().contains("propType")) { - std::string propType = item.value().at("propType"); - - auto fileField = FileField::create(); - fileField->label->setText(item.key()); - fileField->value->setText( - item.value().at("value").get()); - fileField->callback = [&j, item, - this](const tgui::String &filePath) { - printf("%s \n", filePath.toStdString().c_str()); - printf("%s \n", GetFileNameWithoutExt( - filePath.toStdString().c_str())); - auto &ref = j.at(item.key()); - - ref.at("value") = - GetFileNameWithoutExt(filePath.toStdString().c_str()); - }; - - if (propType == "dialogue") { - fileField->pathFilters = {{"Dialogue", {"*.rdiag"}}}; + addTextField(textField); + } + if (item.value().is_number()) { + auto intField = IntField::create(); + intField->label->setText(item.key()); + intField->value->setValue(item.value().get()); + intField->value->onValueChange([&j, item](float value) { j.at(item.key()) = value; }); + addIntField(intField); + } + if (item.value().is_boolean()) { + auto boolField = BoolField::create(); + boolField->label->setText(item.key()); + boolField->value->setChecked(item.value().get()); + boolField->value->onChange([&j, item](bool checked) { j.at(item.key()) = checked; }); + addBooleanField(boolField); + } + if (item.value().is_object()) { + if (item.value().contains("propType")) { + std::string propType = item.value().at("propType"); + + auto fileField = FileField::create(); + fileField->label->setText(item.key()); + fileField->value->setText(item.value().at("value").get()); + fileField->callback = [&j, item, this](const tgui::String &filePath) { + printf("%s \n", filePath.toStdString().c_str()); + printf("%s \n", GetFileNameWithoutExt(filePath.toStdString().c_str())); + auto &ref = j.at(item.key()); + + ref.at("value") = GetFileNameWithoutExt(filePath.toStdString().c_str()); + }; + + if (propType == "dialogue") { + fileField->pathFilters = {{"Dialogue", {"*.rdiag"}}}; + } + + addFileField(fileField); } - - addFileField(fileField); } } } } -tgui::Button::Ptr -PropertiesBox::constructButton(const tgui::String &title, - std::function callback) { +tgui::Button::Ptr PropertiesBox::constructButton(const tgui::String &title, std::function callback) { auto button = tgui::Button::create(title); button->setSize(TextFormat("100%% - %d", PADDING * 2), 24); button->setPosition({PADDING, 0}); @@ -122,13 +186,11 @@ PropertiesBox::constructButton(const tgui::String &title, return button; } -void PropertiesBox::addButton(const tgui::String &title, - std::function callback) { +void PropertiesBox::addButton(const tgui::String &title, std::function callback) { this->constructButton(title, callback); } -void PropertiesBox::addIntField(const tgui::String &title, int initialValue, - std::function callback) { +void PropertiesBox::addIntField(const tgui::String &title, int initialValue, std::function callback) { auto group = tgui::Group::create({"100%", 24}); auto label = tgui::Label::create(title); @@ -176,3 +238,15 @@ void PropertiesBox::addRectangleField(RectangleField::Ptr field) { field->setSize({"100%", 48}); layout->add(field); } + +void PropertiesBox::addInterPropField(InterPropField::Ptr field) { + field->setSize({"100%", 24}); + layout->add(field); +} + +void PropertiesBox::addPropertiesBox(PropertiesBox::Ptr box) { + box->setWidth("80%"); + layout->add(box); +} + +void PropertiesBox::addWidget(tgui::Widget::Ptr widget) { layout->add(widget); } diff --git a/src/editor/widgets/propertyFields/boolField.cpp b/src/editor/widgets/propertyFields/boolField.cpp index 5b88efa8..729f01ea 100644 --- a/src/editor/widgets/propertyFields/boolField.cpp +++ b/src/editor/widgets/propertyFields/boolField.cpp @@ -1,8 +1,8 @@ #include "widgets/propertyFields/boolField.hpp" + #include "TGUI/Widgets/CheckBox.hpp" #include "widgets/propertyFields/fieldConfig.hpp" -BoolField::BoolField(const char *typeName, bool initRenderer) - : tgui::SubwidgetContainer(typeName, initRenderer) { +BoolField::BoolField(const char *typeName, bool initRenderer) : tgui::SubwidgetContainer(typeName, initRenderer) { label = tgui::Label::create("Label"); label->setHorizontalAlignment(tgui::HorizontalAlignment::Left); label->setVerticalAlignment(tgui::VerticalAlignment::Center); @@ -24,9 +24,7 @@ BoolField::Ptr BoolField::copy(BoolField::ConstPtr widget) { } } -tgui::Widget::Ptr BoolField::clone() const { - return std::make_shared(*this); -} +tgui::Widget::Ptr BoolField::clone() const { return std::make_shared(*this); } void BoolField::setSize(const tgui::Layout2d &size) { tgui::SubwidgetContainer::setSize(size); diff --git a/src/editor/widgets/propertyFields/fileField.cpp b/src/editor/widgets/propertyFields/fileField.cpp index 1c1834ec..4ee2fc09 100644 --- a/src/editor/widgets/propertyFields/fileField.cpp +++ b/src/editor/widgets/propertyFields/fileField.cpp @@ -1,14 +1,15 @@ #include "widgets/propertyFields/fileField.hpp" + +#include +#include + #include "TGUI/String.hpp" #include "TGUI/Widgets/Button.hpp" #include "TGUI/Widgets/FileDialog.hpp" #include "editor.hpp" #include "raylib.h" #include "widgets/propertyFields/fieldConfig.hpp" -#include -#include -FileField::FileField(const char *typeName, bool initRenderer) - : tgui::SubwidgetContainer(typeName, initRenderer) { +FileField::FileField(const char *typeName, bool initRenderer) : tgui::SubwidgetContainer(typeName, initRenderer) { label = tgui::Label::create("Label"); label->setHorizontalAlignment(tgui::HorizontalAlignment::Left); label->setVerticalAlignment(tgui::VerticalAlignment::Center); @@ -19,8 +20,7 @@ FileField::FileField(const char *typeName, bool initRenderer) fileDialog->setPath(Editor::instance->getProject()->getBasePath()); fileDialog->setFileTypeFilters(pathFilters); fileDialog->onFileSelect([this](const tgui::String &path) { - value->setText( - std::string(GetFileName(path.toStdString().c_str()))); + value->setText(std::string(GetFileName(path.toStdString().c_str()))); chosenPath = path; if (callback != nullptr) { callback(path); @@ -38,8 +38,7 @@ FileField::FileField(const char *typeName, bool initRenderer) FileField::Ptr FileField::create() { return std::make_shared(); } -FileField::Ptr FileField::create(const tgui::String &label, - const tgui::String &value) { +FileField::Ptr FileField::create(const tgui::String &label, const tgui::String &value) { auto ptr = std::make_shared(); ptr->label->setText(label); ptr->value->setText(value); @@ -54,9 +53,7 @@ FileField::Ptr FileField::copy(FileField::ConstPtr widget) { } } -tgui::Widget::Ptr FileField::clone() const { - return std::make_shared(*this); -} +tgui::Widget::Ptr FileField::clone() const { return std::make_shared(*this); } void FileField::setValue(const tgui::String &value) { this->value->setText(value); diff --git a/src/editor/widgets/propertyFields/intField.cpp b/src/editor/widgets/propertyFields/intField.cpp index eca75356..e5c54022 100644 --- a/src/editor/widgets/propertyFields/intField.cpp +++ b/src/editor/widgets/propertyFields/intField.cpp @@ -1,19 +1,32 @@ #include "widgets/propertyFields/intField.hpp" + +#include + +#include "TGUI/Texture.hpp" #include "TGUI/Widget.hpp" +#include "TGUI/Widgets/BitmapButton.hpp" #include "TGUI/Widgets/Label.hpp" #include "TGUI/Widgets/SpinControl.hpp" +#include "editor.hpp" #include "widgets/propertyFields/fieldConfig.hpp" -#include -IntField::IntField(const char *typeName, bool initRenderer) - : tgui::SubwidgetContainer(typeName, initRenderer) { + +IntField::IntField(const char *typeName, bool initRenderer) : tgui::SubwidgetContainer(typeName, initRenderer) { label = tgui::Label::create("Label"); label->setHorizontalAlignment(tgui::HorizontalAlignment::Left); label->setVerticalAlignment(tgui::VerticalAlignment::Center); value = tgui::SpinControl::create(0, 100); + remove = tgui::BitmapButton::create(); + remove->setSize({0, 0}); m_container->add(label); m_container->add(value); + auto closeImagePath = Editor::instance->getFs().getResourcePath("close.png"); + tgui::Texture imageTexture(closeImagePath); + remove->setImage(imageTexture); + remove->setVisible(false); + m_container->add(remove); + updateSize(); } @@ -27,9 +40,7 @@ IntField::Ptr IntField::copy(IntField::ConstPtr widget) { } } -tgui::Widget::Ptr IntField::clone() const { - return std::make_shared(*this); -} +tgui::Widget::Ptr IntField::clone() const { return std::make_shared(*this); } void IntField::setSize(const tgui::Layout2d &size) { tgui::SubwidgetContainer::setSize(size); @@ -37,9 +48,25 @@ void IntField::setSize(const tgui::Layout2d &size) { } void IntField::updateSize() { - label->setPosition({PADDING, 0}); - label->setSize({getSize().x * 0.5f - PADDING, getSize().y}); - value->setSize({getSize().x * 0.5f - PADDING, getSize().y}); + if (!removable) { + label->setPosition({PADDING, 0}); + label->setSize({getSize().x * 0.5f - PADDING, getSize().y}); + value->setSize({getSize().x * 0.5f - PADDING, getSize().y}); + value->setPosition({getSize().x * 0.5, 0}); + remove->setPosition({0, 0}); + remove->setSize({0, 0}); + } else { + label->setPosition({PADDING, 0}); + label->setSize({getSize().x * 0.4f, getSize().y}); + value->setPosition({getSize().x * 0.4f, 0}); + value->setSize({getSize().x * 0.4f, getSize().y}); + remove->setPosition({getSize().x * 0.8f, 0}); + remove->setSize({getSize().x * 0.2f, getSize().y}); + } +} - value->setPosition({getSize().x * 0.5, 0}); +void IntField::enableRemoving() { + removable = true; + remove->setVisible(true); + updateSize(); } diff --git a/src/editor/widgets/propertyFields/interPropField.cpp b/src/editor/widgets/propertyFields/interPropField.cpp new file mode 100644 index 00000000..fa23cfa8 --- /dev/null +++ b/src/editor/widgets/propertyFields/interPropField.cpp @@ -0,0 +1,52 @@ +#include "widgets/propertyFields/interPropField.hpp" + +#include +#include + +#include "TGUI/Widget.hpp" +#include "TGUI/Widgets/Button.hpp" +#include "TGUI/Widgets/Label.hpp" +#include "childWindows/settingsPanel/base.hpp" +#include "widgets/propertyFields/fieldConfig.hpp" + +InterPropField::InterPropField(const char *typeName, bool initRenderer) + : tgui::SubwidgetContainer(typeName, initRenderer) { + label = tgui::Label::create("Label"); + label->setHorizontalAlignment(tgui::HorizontalAlignment::Left); + label->setVerticalAlignment(tgui::VerticalAlignment::Center); + value = tgui::Button::create(); + remove = tgui::Button::create(); + bindTranslation(remove, "widget.propField.interPropField.remove", &tgui::Button::setText); + + m_container->add(label, "Label"); + m_container->add(value, "Value"); + m_container->add(remove, "Remove"); + + updateSize(); +} + +InterPropField::Ptr InterPropField::create() { return std::make_shared(); } + +InterPropField::Ptr InterPropField::copy(InterPropField::ConstPtr widget) { + if (widget) { + return std::static_pointer_cast(widget->clone()); + } else { + return nullptr; + } +} + +tgui::Widget::Ptr InterPropField::clone() const { return std::make_shared(*this); } + +void InterPropField::setSize(const tgui::Layout2d &size) { + tgui::SubwidgetContainer::setSize(size); + updateSize(); +} + +void InterPropField::updateSize() { + label->setPosition({PADDING, 0}); + label->setSize({getSize().x * 0.33f - PADDING, getSize().y}); + value->setPosition({getSize().x * 0.33f, 0}); + value->setSize({getSize().x * 0.33f, getSize().y}); + remove->setPosition({getSize().x * 0.67f, 0}); + remove->setSize({getSize().x * 0.33f - PADDING, getSize().y}); +} diff --git a/src/editor/widgets/propertyFields/rectangleField.cpp b/src/editor/widgets/propertyFields/rectangleField.cpp index bd1e154b..951331bc 100644 --- a/src/editor/widgets/propertyFields/rectangleField.cpp +++ b/src/editor/widgets/propertyFields/rectangleField.cpp @@ -1,16 +1,18 @@ #include "widgets/propertyFields/rectangleField.hpp" + +#include + #include "TGUI/Layout.hpp" #include "TGUI/Widget.hpp" #include "raylib.h" #include "widgets/propertyFields/fieldConfig.hpp" -#include void setAlign(tgui::Label::Ptr widget) { widget->setHorizontalAlignment(tgui::HorizontalAlignment::Left); widget->setVerticalAlignment(tgui::VerticalAlignment::Center); } -RectangleField::RectangleField(const char *typeName, bool initRenderer) +RectangleField::RectangleField(const char* typeName, bool initRenderer) : tgui::SubwidgetContainer(typeName, initRenderer) { label = tgui::Label::create("Label"); setAlign(label); @@ -20,28 +22,26 @@ RectangleField::RectangleField(const char *typeName, bool initRenderer) value_x = tgui::SpinControl::create(); value_x->setMinimum(INT_MIN); value_x->setMaximum(INT_MAX); - value_x->onValueChange([this](int _) { onChange.emit(this, getValue()); }); + value_x->onValueChange([this](const float& _) { onChange.emit(this, getValue()); }); l_y = tgui::Label::create("Y"); setAlign(l_y); value_y = tgui::SpinControl::create(); value_y->setMinimum(INT_MIN); value_y->setMaximum(INT_MAX); - value_y->onValueChange([this](int _) { onChange.emit(this, getValue()); }); + value_y->onValueChange([this](const float& _) { onChange.emit(this, getValue()); }); l_width = tgui::Label::create("W"); setAlign(l_width); value_width = tgui::SpinControl::create(); value_width->setMaximum(INT_MAX); - value_width->onValueChange( - [this](int _) { onChange.emit(this, getValue()); }); + value_width->onValueChange([this](const float& _) { onChange.emit(this, getValue()); }); l_height = tgui::Label::create("H"); setAlign(l_height); value_height = tgui::SpinControl::create(); value_height->setMaximum(INT_MAX); - value_height->onValueChange( - [this](int _) { onChange.emit(this, getValue()); }); + value_height->onValueChange([this](const float& _) { onChange.emit(this, getValue()); }); m_container->add(label); @@ -66,13 +66,10 @@ void RectangleField::setValue(Rectangle value) { } Rectangle RectangleField::getValue() { - return Rectangle{value_x->getValue(), value_y->getValue(), - value_width->getValue(), value_height->getValue()}; + return Rectangle{value_x->getValue(), value_y->getValue(), value_width->getValue(), value_height->getValue()}; } -RectangleField::Ptr RectangleField::create() { - return std::make_shared(); -} +RectangleField::Ptr RectangleField::create() { return std::make_shared(); } RectangleField::Ptr RectangleField::copy(RectangleField::ConstPtr widget) { if (widget) { @@ -82,11 +79,9 @@ RectangleField::Ptr RectangleField::copy(RectangleField::ConstPtr widget) { } } -tgui::Widget::Ptr RectangleField::clone() const { - return std::make_shared(*this); -} +tgui::Widget::Ptr RectangleField::clone() const { return std::make_shared(*this); } -void RectangleField::setSize(const tgui::Layout2d &size) { +void RectangleField::setSize(const tgui::Layout2d& size) { tgui::SubwidgetContainer::setSize(size); updateSize(); } @@ -108,13 +103,10 @@ void RectangleField::updateSize() { value_y->setSize({fieldW * 0.7, height / 2}); l_width->setPosition({tgui::bindRight(value_y), tgui::bindBottom(label)}); l_width->setSize({fieldW * 0.3, height / 2}); - value_width->setPosition( - {tgui::bindRight(l_width), tgui::bindBottom(label)}); + value_width->setPosition({tgui::bindRight(l_width), tgui::bindBottom(label)}); value_width->setSize({fieldW * 0.7, height / 2}); - l_height->setPosition( - {tgui::bindRight(value_width), tgui::bindBottom(label)}); + l_height->setPosition({tgui::bindRight(value_width), tgui::bindBottom(label)}); l_height->setSize({fieldW * 0.3, height / 2}); - value_height->setPosition( - {tgui::bindRight(l_height), tgui::bindBottom(label)}); + value_height->setPosition({tgui::bindRight(l_height), tgui::bindBottom(label)}); value_height->setSize({fieldW * 0.7, height / 2}); } diff --git a/src/editor/widgets/propertyFields/selectField.cpp b/src/editor/widgets/propertyFields/selectField.cpp index 53535b0f..487c1b19 100644 --- a/src/editor/widgets/propertyFields/selectField.cpp +++ b/src/editor/widgets/propertyFields/selectField.cpp @@ -1,13 +1,14 @@ #include "widgets/propertyFields/selectField.hpp" + +#include + #include "TGUI/Widget.hpp" #include "TGUI/Widgets/ComboBox.hpp" #include "TGUI/Widgets/Group.hpp" #include "TGUI/Widgets/Label.hpp" #include "widgets/propertyFields/fieldConfig.hpp" -#include -SelectField::SelectField(const char *typeName, bool initRenderer) - : tgui::Group(typeName, initRenderer) { +SelectField::SelectField(const char *typeName, bool initRenderer) : tgui::Group(typeName, initRenderer) { label = tgui::Label::create("Label"); label->setHorizontalAlignment(tgui::HorizontalAlignment::Left); label->setVerticalAlignment(tgui::VerticalAlignment::Center); @@ -19,9 +20,7 @@ SelectField::SelectField(const char *typeName, bool initRenderer) updateSize(); } -SelectField::Ptr SelectField::create() { - return std::make_shared(); -} +SelectField::Ptr SelectField::create() { return std::make_shared(); } SelectField::Ptr SelectField::copy(SelectField::ConstPtr widget) { if (widget) { @@ -31,9 +30,7 @@ SelectField::Ptr SelectField::copy(SelectField::ConstPtr widget) { } } -tgui::Widget::Ptr SelectField::clone() const { - return std::make_shared(*this); -} +tgui::Widget::Ptr SelectField::clone() const { return std::make_shared(*this); } void SelectField::setSize(const tgui::Layout2d &size) { tgui::Group::setSize(size); diff --git a/src/editor/widgets/propertyFields/textField.cpp b/src/editor/widgets/propertyFields/textField.cpp index 4e9c66b8..28a315ae 100644 --- a/src/editor/widgets/propertyFields/textField.cpp +++ b/src/editor/widgets/propertyFields/textField.cpp @@ -1,12 +1,16 @@ #include "widgets/propertyFields/textField.hpp" + +#include +#include + +#include "TGUI/Texture.hpp" #include "TGUI/Widget.hpp" +#include "TGUI/Widgets/BitmapButton.hpp" #include "TGUI/Widgets/Label.hpp" +#include "editor.hpp" #include "widgets/propertyFields/fieldConfig.hpp" -#include -#include -TextField::TextField(const char *typeName, bool initRenderer) - : tgui::SubwidgetContainer(typeName, initRenderer) { +TextField::TextField(const char *typeName, bool initRenderer) : tgui::SubwidgetContainer(typeName, initRenderer) { label = tgui::Label::create("Label"); label->setHorizontalAlignment(tgui::HorizontalAlignment::Left); label->setVerticalAlignment(tgui::VerticalAlignment::Center); @@ -28,9 +32,7 @@ TextField::Ptr TextField::copy(TextField::ConstPtr widget) { } } -tgui::Widget::Ptr TextField::clone() const { - return std::make_shared(*this); -} +tgui::Widget::Ptr TextField::clone() const { return std::make_shared(*this); } void TextField::setSize(const tgui::Layout2d &size) { tgui::SubwidgetContainer::setSize(size); @@ -41,6 +43,5 @@ void TextField::updateSize() { label->setPosition({PADDING, 0}); label->setSize({getSize().x * 0.5f - PADDING, getSize().y}); value->setSize({getSize().x * 0.5f - PADDING, getSize().y}); - value->setPosition({getSize().x * 0.5, 0}); } diff --git a/src/editor/widgets/soundPlayer.cpp b/src/editor/widgets/soundPlayer.cpp index 449b94a3..cb0e781f 100644 --- a/src/editor/widgets/soundPlayer.cpp +++ b/src/editor/widgets/soundPlayer.cpp @@ -1,4 +1,7 @@ #include "widgets/soundPlayer.hpp" + +#include + #include "TGUI/SubwidgetContainer.hpp" #include "TGUI/Texture.hpp" #include "TGUI/Widgets/BitmapButton.hpp" @@ -9,14 +12,10 @@ #include "raylib.h" #include "saveables/soundWrapper.hpp" #include "timeFormat.hpp" -#include -SoundPlayer::SoundPlayer(const char *typeName, bool initRenderer) - : tgui::SubwidgetContainer(typeName, initRenderer) { - playTexture = - tgui::Texture(Editor::instance->getFs().getResourcePath("play.png")); - pauseTexture = - tgui::Texture(Editor::instance->getFs().getResourcePath("pause.png")); +SoundPlayer::SoundPlayer(const char *typeName, bool initRenderer) : tgui::SubwidgetContainer(typeName, initRenderer) { + playTexture = tgui::Texture(Editor::instance->getFs().getResourcePath("play.png")); + pauseTexture = tgui::Texture(Editor::instance->getFs().getResourcePath("pause.png")); panel = tgui::Panel::create(); panel->getRenderer()->setPadding({4, 4}); @@ -88,15 +87,12 @@ void SoundPlayer::setSound(SoundWrapper *sound) { slider->setStep(1.0f); slider->setValue(0.0f); - timeLabel->setText(TextFormat( - "0:00 | %s", formatTime(GetMusicTimeLength(sound->sound)).c_str())); + timeLabel->setText(TextFormat("0:00 | %s", formatTime(GetMusicTimeLength(sound->sound)).c_str())); } SoundWrapper *SoundPlayer::getSound() { return sound; } -SoundPlayer::Ptr SoundPlayer::create() { - return std::make_shared(); -} +SoundPlayer::Ptr SoundPlayer::create() { return std::make_shared(); } SoundPlayer::Ptr SoundPlayer::copy(SoundPlayer::ConstPtr widget) { if (widget) @@ -111,15 +107,12 @@ void SoundPlayer::update() { slider->setValue(GetMusicTimePlayed(sound->sound)); - timeLabel->setText(TextFormat( - "%s | %s", formatTime(GetMusicTimePlayed(sound->sound)).c_str(), - formatTime(GetMusicTimeLength(sound->sound)).c_str())); + timeLabel->setText(TextFormat("%s | %s", formatTime(GetMusicTimePlayed(sound->sound)).c_str(), + formatTime(GetMusicTimeLength(sound->sound)).c_str())); } } -tgui::Widget::Ptr SoundPlayer::clone() const { - return std::make_shared(*this); -} +tgui::Widget::Ptr SoundPlayer::clone() const { return std::make_shared(*this); } void SoundPlayer::setSize(const tgui::Layout2d &size) { tgui::SubwidgetContainer::setSize(size); diff --git a/src/game.cpp b/src/game.cpp index aa803f37..2846715e 100644 --- a/src/game.cpp +++ b/src/game.cpp @@ -1,22 +1,23 @@ #include "game.hpp" -#include "gamedata.hpp" -#include "scriptService.hpp" -#include "soundService.hpp" -#include + #include + +#include #include -#include // FIXME : lua.h not found +#include // FIXME : lua.h not found #include +#include "gamedata.hpp" +#include "scriptService.hpp" +#include "soundService.hpp" + Game *Game::instance_ = nullptr; std::unique_ptr Game::gameData = std::unique_ptr{}; bool Game::usesBin = false; std::unique_ptr Game::state = std::unique_ptr{}; std::unique_ptr Game::world = std::unique_ptr{}; -std::unique_ptr Game::ui = - std::unique_ptr{}; -std::unique_ptr Game::resources = - std::unique_ptr{}; +std::unique_ptr Game::ui = std::unique_ptr{}; +std::unique_ptr Game::resources = std::unique_ptr{}; std::unique_ptr Game::sounds = std::unique_ptr{}; std::unique_ptr Game::scripts = std::unique_ptr{}; @@ -47,21 +48,48 @@ void Game::init() { scripts = std::make_unique(); } +bool Game::isUsingBin() { return usesBin; } + void Game::useBin(const std::string &filePath) { gameData = std::make_unique(deserializeFile(filePath)); usesBin = true; - for (const auto &[name, data] : gameData->images) { - Image image = LoadImageFromMemory(data.ext.c_str(), data.data.data(), - data.dataSize); - Texture2D texture = LoadTextureFromImage(image); - resources->addTexture(name, texture); - UnloadImage(image); - } + // resources + resources->init(); + /// Setup program SetWindowTitle(gameData->title.c_str()); + SetWindowSize(gameData->programSet.windowSize.x, gameData->programSet.windowSize.y); + if (gameData->programSet.windowResizeableFlag) { + SetWindowState(FLAG_WINDOW_RESIZABLE); + } else { + ClearWindowState(FLAG_WINDOW_RESIZABLE); + } + SetWindowState(gameData->programSet.windowStateFlag); + if (gameData->programSet.targetFPS > 0) { + SetTargetFPS(gameData->programSet.targetFPS); + } - world->setRoomBin(gameData->rooms.at(0)); + auto iconTexture = resources->getTexture(GetFileName(gameData->programSet.programIconPath.c_str())); + Image iconImage = LoadImageFromTexture(iconTexture); + + SetWindowIcon(iconImage); + + UnloadImage(iconImage); + /// + + /// Select the default room from the settings + if (gameData->gameSet.defaultRoomPath.empty()) { + world->setRoomBin(gameData->rooms.at(0)); + } else { + std::string chosenName = GetFileNameWithoutExt(gameData->gameSet.defaultRoomPath.c_str()); + for (auto &room : gameData->rooms) { + if (room.name == chosenName) { + world->setRoomBin(room); + break; + } + } + } } GameData &Game::getBin() { return *gameData; } diff --git a/src/game/main.cpp b/src/game/main.cpp index adca19a4..b1513d88 100644 --- a/src/game/main.cpp +++ b/src/game/main.cpp @@ -1,6 +1,7 @@ -#include "game.hpp" #include +#include "game.hpp" + int main() { const int width = 640; const int height = 480; diff --git a/src/gamedata.cpp b/src/gamedata.cpp index 21de4833..2d5d7e95 100644 --- a/src/gamedata.cpp +++ b/src/gamedata.cpp @@ -1,91 +1,137 @@ #include "gamedata.hpp" -#include "interactable.hpp" -#include +#include #include #include #include #include +#include -#include +#include "dialogueBalloon.hpp" +#include "interactable.hpp" +#include "raylib.h" -template void serialize(Archive &a, IRect &b) { +template +void serialize(Archive &a, IRect &b) { a(b.x, b.y, b.width, b.height); } -template void serialize(Archive &a, IVector &b) { a(b.x, b.y); } +template +void serialize(Archive &a, IVector &b) { + a(b.x, b.y); +} + +template +void serialize(Archive &a, Color &b) { + a(b.a, b.r, b.g, b.b); +} -template void serialize(Archive &a, ActorBin &b) { +template +void serialize(Archive &a, ActorBin &b) { a(b.name, b.tileSetName, b.collision, b.animations); } -template void serialize(Archive &a, ActorInRoomBin &b) { - a(b.name, b.source, b.tilePos); +template +void serialize(Archive &a, ActorInRoomBin &b) { + a(b.name, b.source, b.tilePos, b.intType, b.propsCbor); } -template void serialize(Archive &a, TileBin &b) { +template +void serialize(Archive &a, TileBin &b) { a(b.atlasPos, b.worldPos); } -template void serialize(Archive &a, InteractableBin &b) { +template +void serialize(Archive &a, InteractableBin &b) { a(b.typeName, b.scriptPath, b.props); } -template void serialize(Archive &a, InteractableInRoomBin &b) { +template +void serialize(Archive &a, InteractableInRoomBin &b) { a(b.x, b.y, b.onTouch, b.propsCbor, b.type); } -template void serialize(Archive &a, PropInRoomBin &b) { +template +void serialize(Archive &a, PropInRoomBin &b) { a(b.name, b.tilePos, b.onTouch, b.propsCbor); } -template void serialize(Archive &a, TileSetBin &b) { +template +void serialize(Archive &a, TileSetBin &b) { a(b.name, b.extension, b.tileSize, b.image, b.dataSize); } -template void serialize(Archive &a, ImageBin &b) { +template +void serialize(Archive &a, FontBin &b) { a(b.data, b.dataSize, b.ext); } -template void serialize(Archive &a, MusicBin &b) { +template +void serialize(Archive &a, ImageBin &b) { + a(b.data, b.dataSize, b.ext); +} + +template +void serialize(Archive &a, MusicBin &b) { a(b.relativePath, b.isSound, b.fileData, b.fileExt); } -template void serialize(Archive &a, PropBin &b) { - a(b.name, b.atlasRect, b.collisionRect, b.imagePath, b.hasInteractable, - b.intType); +template +void serialize(Archive &a, PropBin &b) { + a(b.name, b.atlasRect, b.collisionRect, b.imagePath, b.hasInteractable, b.intType); +} + +template +void serialize(Archive &a, RoomBin &b) { + a(b.name, b.tileSetName, b.width, b.height, b.startPoint, b.collisions, b.interactables, b.props, b.actors, b.tiles, + b.musicSource); } -template void serialize(Archive &a, RoomBin &b) { - a(b.name, b.tileSetName, b.width, b.height, b.startPoint, b.collisions, - b.interactables, b.props, b.actors, b.tiles, b.musicSource); +template +void serialize(Archive &a, DialogueTextSection &b) { + a(b.key, b.text, b.textColor, b.textSize, b.font, b.delay, b.padding, b.paddingMode, b.sound, b.newline); } -template void serialize(Archive &a, DialogueTextSection &b) { - a(b.key, b.text); +template +void serialize(Archive &a, DialogueOption &b) { + a(b.title, b.nextDialogue); } -template void serialize(Archive &a, DialogueLine &b) { - a(b.text, b.sections, b.imageId, b.hasPortrait, b.characterName); +template +void serialize(Archive &a, DialogueLine &b) { + a(b.text, b.sections, b.imageId, b.hasPortrait, b.characterName, b.hasOptions, b.options); } -template void serialize(Archive &a, DialogueBin &b) { +template +void serialize(Archive &a, DialogueBin &b) { a(b.title, b.lines); } -template void serialize(Archive &a, GameData &b) { - a(b.title, b.images, b.tilesets, b.rooms, b.actors, b.props, b.dialogues, - b.music, b.interactables, b.scripts); +template +void serialize(Archive &a, ProjectProgramSettings &b) { + a(b.projectTitle, b.projectVersion, b.windowSize, b.programIconPath, b.windowResizeableFlag, b.windowStateFlag, + b.targetFPS); +} + +template +void serialize(Archive &a, ProjectGameSettings &b) { + a(b.defaultRoomPath, b.playerActorPath, b.tileSize, b.debugDraw, b.exportImageScales, b.exportFontSizes); +} + +template +void serialize(Archive &a, GameData &b) { + a(b.title, b.programSet, b.gameSet, b.images, b.fonts, b.tilesets, b.rooms, b.actors, b.props, b.dialogues, b.music, + b.interactables, b.scripts); } -template void serialize(Archive &a, ScriptBin &b) { +template +void serialize(Archive &a, ScriptBin &b) { a(b.bytecode); } void serializeDataToFile(std::string fileName, GameData data) { { - std::fstream os{fileName, std::ifstream::binary | std::fstream::trunc | - std::fstream::out}; + std::fstream os{fileName, std::ifstream::binary | std::fstream::trunc | std::fstream::out}; if (!os.is_open()) { printf("Cannot open %s for writing. \n", fileName.c_str()); return; diff --git a/src/imageRect.cpp b/src/imageRect.cpp index ecf3ca27..840ec749 100644 --- a/src/imageRect.cpp +++ b/src/imageRect.cpp @@ -1,7 +1,9 @@ #include "imageRect.hpp" -#include + #include +#include + ImageRect::ImageRect() : rect(Rectangle{}), texture() {} ImageRect::ImageRect(Rectangle rect) : texture() { @@ -16,8 +18,6 @@ void ImageRect::setTexture(Texture2D texture) { this->texture = texture; } void ImageRect::update() {} void ImageRect::draw() { - DrawTexturePro(texture, - Rectangle{0, 0, static_cast(texture.width), - static_cast(texture.height)}, + DrawTexturePro(texture, Rectangle{0, 0, static_cast(texture.width), static_cast(texture.height)}, rect, Vector2{0, 0}, 0.0f, WHITE); } diff --git a/src/interactable.cpp b/src/interactable.cpp index f2b61416..ba782fdd 100644 --- a/src/interactable.cpp +++ b/src/interactable.cpp @@ -1,4 +1,13 @@ #include "interactable.hpp" + +#include +#include + +#include +#include +#include +#include + #include "actor.hpp" #include "game.hpp" #include "gamedata.hpp" @@ -8,15 +17,8 @@ #include "sol/state_handling.hpp" #include "sol/types.hpp" #include "tilemap.hpp" -#include -#include -#include -#include -#include -#include -Interactable::Interactable() - : type(), tilePos(), tileSize(0), absolutePos(), rect() { +Interactable::Interactable() : type(), tilePos(), tileSize(0), absolutePos(), rect() { this->valid = false; this->onTouch = false; } @@ -30,11 +32,10 @@ Interactable::Interactable(const std::string &path) { displayTitle = intJson.at("name"); props = std::make_unique(intJson.at("props")); scriptPath = intJson.at("script"); - onTouch = false; + onTouch = intJson.at("onTouch"); } -Interactable::Interactable(const std::string &type, Vector2 tilePos, - int tileSize) { +Interactable::Interactable(const std::string &type, Vector2 tilePos, int tileSize) { this->type = type; this->props = std::make_unique(json::object()); @@ -45,15 +46,13 @@ Interactable::Interactable(const std::string &type, Vector2 tilePos, this->tileSize = tileSize; this->absolutePos = Vector2{0, 0}; - rect = - Rectangle{tilePos.x * tileSize, tilePos.y * tileSize, - static_cast(tileSize), static_cast(tileSize)}; + rect = Rectangle{tilePos.x * tileSize, tilePos.y * tileSize, static_cast(tileSize), + static_cast(tileSize)}; } Interactable::Interactable(InteractableInRoomBin bin) { this->type = bin.type; - this->props = - std::make_unique(json::from_cbor(bin.propsCbor)); + this->props = std::make_unique(json::from_cbor(bin.propsCbor)); Vector2 tilePos = {static_cast(bin.x), static_cast(bin.y)}; @@ -63,15 +62,15 @@ Interactable::Interactable(InteractableInRoomBin bin) { this->tileSize = _RPGPP_TILESIZE; this->absolutePos = Vector2{0, 0}; - rect = - Rectangle{tilePos.x * tileSize, tilePos.y * tileSize, - static_cast(tileSize), static_cast(tileSize)}; + rect = Rectangle{tilePos.x * tileSize, tilePos.y * tileSize, static_cast(tileSize), + static_cast(tileSize)}; } json Interactable::dumpJson() { json j = json::object(); j.push_back({"name", displayTitle}); j.push_back({"props", *props}); + j.push_back({"onTouch", onTouch}); j.push_back({"script", scriptPath}); return j; @@ -94,25 +93,50 @@ void Interactable::setType(const std::string &type) { this->props = std::make_unique(json::object()); } -void Interactable::setProps(nlohmann::json j) { - this->props = std::make_unique(j); +void Interactable::setProps(nlohmann::json j) { this->props = std::make_unique(j); } + +void Interactable::addProp(PropType propType, const std::string &name) { + switch (propType) { + case PROP_INT: + props->push_back({name, 0}); + break; + case PROP_STRING: + props->push_back({name, ""}); + break; + case PROP_BOOLEAN: + props->push_back({name, false}); + break; + case PROP_DIALOGUE: + props->push_back({name, {{"propType", "dialogue"}, {"value", ""}}}); + break; + default: + break; + } } nlohmann::json &Interactable::getProps() { return *props; } +nlohmann::json *Interactable::getPropsPtr() { return props.get(); } + +void Interactable::setScriptSourcePath(const std::string &newPath) { scriptPath = newPath; } + const std::string &Interactable::getScriptSourcePath() { return scriptPath; } -void Interactable::setDisplayTitle(const std::string &newTitle) { - displayTitle = newTitle; -} +void Interactable::setDisplayTitle(const std::string &newTitle) { displayTitle = newTitle; } std::string &Interactable::getDisplayTitle() { return displayTitle; } void Interactable::interact() { + if (type.empty()) { + printf("%s \n", "Warning: This Interactable's type is empty."); + return; + } + auto &state = Game::getScripts().getState(); Game::getScripts().addToState(*props); state["this"] = this; + state["self"] = this; auto intBin = Game::getBin().interactables.at(type); if (Game::getBin().scripts.count(intBin.scriptPath) != 0) { diff --git a/src/interactablesContainer.cpp b/src/interactablesContainer.cpp index 5f9e575e..9ed8abf4 100644 --- a/src/interactablesContainer.cpp +++ b/src/interactablesContainer.cpp @@ -1,22 +1,24 @@ #include "interactablesContainer.hpp" -#include "conversion.hpp" -#include "game.hpp" -#include "gamedata.hpp" -#include "interactable.hpp" -#include "tilemap.hpp" + +#include + #include #include #include -#include #include #include #include #include +#include "conversion.hpp" +#include "game.hpp" +#include "gamedata.hpp" +#include "interactable.hpp" +#include "tilemap.hpp" + InteractablesContainer::InteractablesContainer() {} -Interactable *InteractablesContainer::add(IVector pos, - const std::string &type) { +Interactable *InteractablesContainer::add(IVector pos, const std::string &type) { if (this->objectExistsAtPosition(pos)) { return nullptr; } @@ -24,8 +26,7 @@ Interactable *InteractablesContainer::add(IVector pos, printf("%s \n", type.c_str()); Vector2 tilePos = fromIVector(pos); - this->pushObject(pos, std::move(std::make_unique( - type, tilePos, _RPGPP_TILESIZE))); + this->pushObject(pos, std::move(std::make_unique(type, tilePos, _RPGPP_TILESIZE))); return this->getObjectAtPosition(pos).get(); } @@ -39,8 +40,7 @@ void InteractablesContainer::addBin(InteractableInRoomBin bin) { this->pushObject(pos, std::move(std::make_unique(bin))); } -void InteractablesContainer::addBinFromTypename(Vector2 pos, - const std::string &type) { +void InteractablesContainer::addBinFromTypename(Vector2 pos, const std::string &type) { if (Game::getBin().interactables.count(type) > 0) { auto interactable = Game::getBin().interactables[type]; InteractableInRoomBin intBin; @@ -53,23 +53,18 @@ void InteractablesContainer::addBinFromTypename(Vector2 pos, addBin(intBin); } else { - throw std::runtime_error(TextFormat( - "This Interactable type does not exist: %s", type.c_str())); + throw std::runtime_error(TextFormat("This Interactable type does not exist: %s", type.c_str())); } } Interactable *InteractablesContainer::getInt(IVector pos) { - if (!this->objectExistsAtPosition(pos)) - return nullptr; + if (!this->objectExistsAtPosition(pos)) return nullptr; return this->getObjectAtPosition(pos).get(); } -Interactable *InteractablesContainer::getIntVec2(Vector2 pos) { - return getInt(fromVector2(pos)); -} +Interactable *InteractablesContainer::getIntVec2(Vector2 pos) { return getInt(fromVector2(pos)); } -void InteractablesContainer::setInteractableType(IVector pos, - const std::string &type) { +void InteractablesContainer::setInteractableType(IVector pos, const std::string &type) { auto &obj = this->getObjectAtPosition(pos); if (obj->getType() == type) { @@ -87,8 +82,7 @@ std::vector InteractablesContainer::getList() { return result; } -void InteractablesContainer::addBinVector( - const std::vector &bin) { +void InteractablesContainer::addBinVector(const std::vector &bin) { for (auto intBin : bin) { addBin(intBin); } @@ -100,8 +94,7 @@ void InteractablesContainer::addJsonData(json roomJson) { for (auto const [key, inter] : map) { int count = 0; char **textSplit = TextSplit(key.c_str(), ';', &count); - if (count != 2) - return; + if (count != 2) return; int x = std::stoi(std::string(textSplit[0])); int y = std::stoi(std::string(textSplit[1])); diff --git a/src/interfaceService.cpp b/src/interfaceService.cpp index 8de9c8bc..c33ce297 100644 --- a/src/interfaceService.cpp +++ b/src/interfaceService.cpp @@ -1,32 +1,34 @@ #include "interfaceService.hpp" + +#include + +#include + #include "colorRect.hpp" #include "game.hpp" #include "imageRect.hpp" #include "interfaceView.hpp" #include "textArea.hpp" -#include -#include InterfaceService::InterfaceService() { fpsVisible = false; - this->font = LoadFontEx("LanaPixel.ttf", 13, nullptr, 250); + // this->font = LoadFontEx("fonts/LanaPixel.ttf", 13, nullptr, 250); + this->font = Game::getResources().getFont("LanaPixel"); - Image img = LoadImage("ui-npatch.png"); + Image img = LoadImage("images/ui-npatch.png"); ImageResizeNN(&img, img.width * 3, img.height * 3); this->uiTexture = LoadTextureFromImage(img); - Rectangle destRec = - Rectangle{0, 0, static_cast(GetScreenWidth() - 20), 140}; + Rectangle destRec = Rectangle{0, 0, static_cast(GetScreenWidth() - 20), 140}; destRec.x = (GetScreenWidth() - destRec.width) / 2; destRec.y = (GetScreenHeight() - destRec.height) - 20; this->dialogue = DialogueBalloon(destRec); this->views = std::make_unique>(); - Rectangle screenRect = Rectangle{0, 0, static_cast(GetScreenWidth()), - static_cast(GetScreenHeight())}; + Rectangle screenRect = Rectangle{0, 0, static_cast(GetScreenWidth()), static_cast(GetScreenHeight())}; InterfaceView view = InterfaceView(screenRect); TextArea *tArea = new TextArea(Rectangle{0, 0, 300, 200}); @@ -58,14 +60,11 @@ void InterfaceService::showDialogue(const std::string &id) { auto diag = Game::getBin().dialogues[id]; showDialogue(diag); } else { - throw std::runtime_error( - TextFormat("This Dialogue does not exist: %s", id.c_str())); + throw std::runtime_error(TextFormat("This Dialogue does not exist: %s", id.c_str())); } } -void InterfaceService::showDialogue(const DialogueBin &dialogue) { - this->dialogue.showDialogue(dialogue); -} +void InterfaceService::showDialogue(const DialogueBin &dialogue) { this->dialogue.showDialogue(dialogue); } void InterfaceService::update() { if (IsKeyPressed(KEY_Q)) { @@ -82,8 +81,7 @@ void InterfaceService::update() { void InterfaceService::draw() { if (fpsVisible) { DrawFPS(10, 10); - DrawTextEx(font, "rpgpp", Vector2{10, 36}, - static_cast(font.baseSize), 2, RED); + DrawTextEx(font, "rpgpp", Vector2{10, 36}, static_cast(font.baseSize), 2, RED); } dialogue.draw(); @@ -93,7 +91,4 @@ void InterfaceService::draw() { } } -void InterfaceService::unload() const { - UnloadFont(font); - UnloadTexture(this->uiTexture); -} +void InterfaceService::unload() const { UnloadTexture(this->uiTexture); } diff --git a/src/interfaceView.cpp b/src/interfaceView.cpp index 2ce6414f..a2080400 100644 --- a/src/interfaceView.cpp +++ b/src/interfaceView.cpp @@ -1,7 +1,9 @@ #include "interfaceView.hpp" -#include "uiElement.hpp" + #include +#include "uiElement.hpp" + InterfaceView::InterfaceView() : rect(Rectangle{}) {} InterfaceView::InterfaceView(Rectangle rect) { diff --git a/src/lua/apiTypes.cpp b/src/lua/apiTypes.cpp index ffd978d0..1638cc3e 100644 --- a/src/lua/apiTypes.cpp +++ b/src/lua/apiTypes.cpp @@ -1,4 +1,8 @@ #include "lua/apiTypes.hpp" + +#include +#include + #include "actor.hpp" #include "actorContainer.hpp" #include "collisionsContainer.hpp" @@ -11,13 +15,9 @@ #include "sol/forward.hpp" #include "sol/raii.hpp" #include "tilemap.hpp" -#include -#include -void lua_interactable_setprop(Interactable *inter, sol::object key, - sol::object value) { - if (inter == nullptr) - return; +void lua_interactable_setprop(Interactable *inter, sol::object key, sol::object value) { + if (inter == nullptr) return; auto &props = inter->getProps(); if (!key.is()) { @@ -49,75 +49,53 @@ void lua_interactable_setprop(Interactable *inter, sol::object key, void lua_types_set(sol::state_view lua) { lua.new_usertype( - "Vector2", - sol::factories([]() { return Vector2(); }, - [](float a, float b) { return Vector2{a, b}; }), - "x", &Vector2::x, "y", &Vector2::y); - - lua.new_enum("Direction", "DOWN_IDLE", Direction::RPGPP_DOWN_IDLE, "DOWN", - Direction::RPGPP_DOWN, "UP_IDLE", Direction::RPGPP_UP_IDLE, - "UP", Direction::RPGPP_UP, "LEFT_IDLE", - Direction::RPGPP_LEFT_IDLE, "LEFT", Direction::RPGPP_LEFT, - "RIGHT_IDLE", Direction::RPGPP_RIGHT_IDLE, "RIGHT", - Direction::RPGPP_RIGHT); - - lua.new_usertype( - sol::no_construction(), "Push", &CollisionsContainer::pushObjectVec2, - "Remove", &CollisionsContainer::removeObjectVec2, "Exists", - &CollisionsContainer::objectExistsAtPositionVec2); + "Vector2", sol::factories([]() { return Vector2(); }, [](float a, float b) { return Vector2{a, b}; }), "x", + &Vector2::x, "y", &Vector2::y); + + lua.new_enum("Direction", "DOWN_IDLE", Direction::RPGPP_DOWN_IDLE, "DOWN", Direction::RPGPP_DOWN, "UP_IDLE", + Direction::RPGPP_UP_IDLE, "UP", Direction::RPGPP_UP, "LEFT_IDLE", Direction::RPGPP_LEFT_IDLE, "LEFT", + Direction::RPGPP_LEFT, "RIGHT_IDLE", Direction::RPGPP_RIGHT_IDLE, "RIGHT", Direction::RPGPP_RIGHT); + + lua.new_usertype(sol::no_construction(), "Push", &CollisionsContainer::pushObjectVec2, + "Remove", &CollisionsContainer::removeObjectVec2, "Exists", + &CollisionsContainer::objectExistsAtPositionVec2); lua.new_usertype( - sol::no_construction(), "Push", - &InteractablesContainer::addBinFromTypename, "Remove", - &InteractablesContainer::removeObjectVec2, "Exists", - &InteractablesContainer::objectExistsAtPositionVec2, "GetAt", - &InteractablesContainer::getIntVec2); - - lua.new_usertype( - sol::no_construction(), "SetProp", &lua_interactable_setprop, - "IsOnTouch", &Interactable::isOnTouch, "SetOnTouch", - &Interactable::setOnTouch, "GetPosition", &Interactable::getWorldPos, - "GetType", &Interactable::getType, "SetType", &Interactable::setType); - - lua.new_usertype( - sol::no_construction(), "Push", &PropsContainer::addProp, "Remove", - &PropsContainer::removeObjectVec2, "Exists", - &PropsContainer::objectExistsAtPositionVec2, "GetAt", - &PropsContainer::getPropAt); - - lua.new_usertype( - sol::no_construction(), "GetPosition", &Prop::getWorldPos, - "SetPosition", &Prop::setWorldPos, "GetTilePosition", - &Prop::getWorldTilePos, "SetTilePosition", &Prop::setWorldTilePos, - "GetInteractable", &Prop::getInteractable); - - lua.new_usertype( - sol::no_construction(), "Push", &ActorContainer::addActor, "Remove", - &ActorContainer::removeActor, "Exists", &ActorContainer::actorExists, - "Get", &ActorContainer::getActor); - - lua.new_usertype( - sol::no_construction(), "GetPlayer", &Room::getPlayer, "GetStartTile", - &Room::getStartTile, "GetTileMap", &Room::getTileMap, "GetCollisions", - &Room::getCollisions, "GetInteractables", &Room::getInteractables, - "GetProps", &Room::getProps, "GetActors", &Room::getActors); - - lua.new_usertype(sol::no_construction(), "SetTile", - &TileMap::setTile, "SetEmptyTile", - &TileMap::setEmptyTile, "GetWorldSizeInTiles", - &TileMap::getMaxWorldSize); - - lua.new_usertype( - sol::no_construction(), "GetPosition", &Actor::getPosition, - "SetPosition", &Actor::setPosition, "GetTilePosition", - &Actor::getTilePosition, "SetTilePosition", &Actor::setTilePosition, - "MoveByVelocity", &Actor::moveByVelocity, "ChangeAnimation", - &Actor::changeAnimation, "PlayAnimation", &Actor::playAnimation); - - lua.new_usertype( - sol::no_construction(), "GetPosition", &Player::getPosition, - "SetPosition", &Player::setPosition, "GetTilePosition", - &Player::getTilePosition, "SetTilePosition", &Player::setTilePosition, - "MoveByVelocity", &Player::moveByVelocity, "GetActor", - &Player::getActor); + sol::no_construction(), "Push", &InteractablesContainer::addBinFromTypename, "Remove", + &InteractablesContainer::removeObjectVec2, "Exists", &InteractablesContainer::objectExistsAtPositionVec2, + "GetAt", &InteractablesContainer::getIntVec2); + + lua.new_usertype(sol::no_construction(), "SetProp", &lua_interactable_setprop, "IsOnTouch", + &Interactable::isOnTouch, "SetOnTouch", &Interactable::setOnTouch, "GetPosition", + &Interactable::getWorldPos, "GetType", &Interactable::getType, "SetType", + &Interactable::setType); + + lua.new_usertype(sol::no_construction(), "Push", &PropsContainer::addProp, "Remove", + &PropsContainer::removeObjectVec2, "Exists", + &PropsContainer::objectExistsAtPositionVec2, "GetAt", &PropsContainer::getPropAt); + + lua.new_usertype(sol::no_construction(), "GetPosition", &Prop::getWorldPos, "SetPosition", &Prop::setWorldPos, + "GetTilePosition", &Prop::getWorldTilePos, "SetTilePosition", &Prop::setWorldTilePos, + "GetInteractable", &Prop::getInteractable); + + lua.new_usertype(sol::no_construction(), "Push", &ActorContainer::addActor, "Remove", + &ActorContainer::removeActor, "Exists", &ActorContainer::actorExists, "Get", + &ActorContainer::getActor); + + lua.new_usertype(sol::no_construction(), "GetPlayer", &Room::getPlayer, "GetStartTile", &Room::getStartTile, + "GetTileMap", &Room::getTileMap, "GetCollisions", &Room::getCollisions, "GetInteractables", + &Room::getInteractables, "GetProps", &Room::getProps, "GetActors", &Room::getActors); + + lua.new_usertype(sol::no_construction(), "SetTile", &TileMap::setTile, "SetEmptyTile", + &TileMap::setEmptyTile, "GetWorldSizeInTiles", &TileMap::getMaxWorldSize); + + lua.new_usertype(sol::no_construction(), "GetPosition", &Actor::getPosition, "SetPosition", + &Actor::setPosition, "GetTilePosition", &Actor::getTilePosition, "SetTilePosition", + &Actor::setTilePosition, "MoveByVelocity", &Actor::moveByVelocity, "ChangeAnimation", + &Actor::changeAnimation, "PlayAnimation", &Actor::playAnimation); + + lua.new_usertype(sol::no_construction(), "GetPosition", &Player::getPosition, "SetPosition", + &Player::setPosition, "GetTilePosition", &Player::getTilePosition, "SetTilePosition", + &Player::setTilePosition, "MoveByVelocity", &Player::moveByVelocity, "GetActor", + &Player::getActor); } \ No newline at end of file diff --git a/src/lua/interfaceApi.cpp b/src/lua/interfaceApi.cpp index 317c1b5c..1f6f33a8 100644 --- a/src/lua/interfaceApi.cpp +++ b/src/lua/interfaceApi.cpp @@ -1,4 +1,5 @@ #include "lua/interfaceApi.hpp" + #include "game.hpp" #include "sol/table.hpp" diff --git a/src/lua/soundsApi.cpp b/src/lua/soundsApi.cpp index 9ffa507c..38c879ef 100644 --- a/src/lua/soundsApi.cpp +++ b/src/lua/soundsApi.cpp @@ -1,22 +1,19 @@ #include "lua/soundsApi.hpp" + +#include + #include "game.hpp" #include "soundService.hpp" -#include -void lua_sounds_loadMusic(const std::string &id) { - Game::getSounds().loadMusic(id); -} +void lua_sounds_loadMusic(const std::string &id) { Game::getSounds().loadMusic(id); } void lua_sounds_playMusic() { Game::getSounds().playMusic(); } -void lua_sounds_playSound(const std::string &id) { - Game::getSounds().playSound(id); -} +void lua_sounds_playSound(const std::string &id) { Game::getSounds().playSound(id); } void lua_sounds_set(sol::state_view &lua) { auto space = lua["Sounds"].get_or_create(); - space.set_function("PlaySound", &SoundService::playSound, - Game::getSounds()); + space.set_function("PlaySound", &SoundService::playSound, Game::getSounds()); space.set_function("LoadMusic", lua_sounds_loadMusic); space.set_function("PlayMusic", lua_sounds_playMusic); } \ No newline at end of file diff --git a/src/lua/stateApi.cpp b/src/lua/stateApi.cpp index 09daa7c8..4648b1e5 100644 --- a/src/lua/stateApi.cpp +++ b/src/lua/stateApi.cpp @@ -1,4 +1,5 @@ #include "lua/stateApi.hpp" + #include "game.hpp" #include "sol/forward.hpp" #include "sol/table.hpp" @@ -21,9 +22,7 @@ void lua_gamestate_setval(const std::string &prop, sol::object value) { } } -Value lua_gamestate_getval(const std::string &prop) { - return Game::getState().getProp(prop); -} +Value lua_gamestate_getval(const std::string &prop) { return Game::getState().getProp(prop); } void lua_gamestate_set(sol::state_view lua) { auto space = lua["GameState"].get_or_create(); diff --git a/src/lua/worldApi.cpp b/src/lua/worldApi.cpp index 6f46437b..b0c42292 100644 --- a/src/lua/worldApi.cpp +++ b/src/lua/worldApi.cpp @@ -1,21 +1,16 @@ #include "lua/worldApi.hpp" + #include "game.hpp" #include "sol/forward.hpp" #include "sol/object.hpp" #include "sol/table.hpp" #include "sol/types.hpp" -sol::object lua_world_getroom(sol::this_state lua) { - return sol::make_object(lua, &Game::getWorld().getRoom()); -} +sol::object lua_world_getroom(sol::this_state lua) { return sol::make_object(lua, &Game::getWorld().getRoom()); } -void lua_world_setroom(const std::string &room) { - Game::getWorld().setRoomBin(room); -} +void lua_world_setroom(const std::string &room) { Game::getWorld().setRoomBin(room); } -sol::object lua_world_getplayer(sol::this_state lua) { - return sol::make_object(lua, &Game::getWorld().getPlayer()); -} +sol::object lua_world_getplayer(sol::this_state lua) { return sol::make_object(lua, &Game::getWorld().getPlayer()); } void lua_world_set(sol::state_view lua) { auto space = lua["World"].get_or_create(); diff --git a/src/player.cpp b/src/player.cpp index e99d4fad..98df0029 100644 --- a/src/player.cpp +++ b/src/player.cpp @@ -1,10 +1,14 @@ #include "player.hpp" -#include "conversion.hpp" -#include "interactable.hpp" + #include #include + #include +#include "conversion.hpp" +#include "game.hpp" +#include "interactable.hpp" + Player::Player(std::unique_ptr actor, Room &room) : room(room) { this->lock = false; this->position = Vector2{0, 0}; @@ -13,8 +17,7 @@ Player::Player(std::unique_ptr actor, Room &room) : room(room) { Rectangle collisionRect = actor->getCollisionRect(Vector2{0, 0}); this->interactableArea = - Rectangle{collisionRect.x - 6, collisionRect.y - 6, - collisionRect.width + 12, collisionRect.height + 12}; + Rectangle{collisionRect.x - 6, collisionRect.y - 6, collisionRect.width + 12, collisionRect.height + 12}; this->actor = std::move(actor); this->idleDirection = RPGPP_DOWN_IDLE; @@ -28,8 +31,7 @@ void Player::unload() const { actor->unload(); } void Player::update() { Rectangle collisionRect = actor->getCollisionRect(Vector2{0, 0}); this->interactableArea = - Rectangle{collisionRect.x - 6, collisionRect.y - 6, - collisionRect.width + 12, collisionRect.height + 12}; + Rectangle{collisionRect.x - 6, collisionRect.y - 6, collisionRect.width + 12, collisionRect.height + 12}; int change = 2; velocity = Vector2{0, 0}; @@ -58,11 +60,9 @@ void Player::update() { this->handleInteraction(); } - if (!lock) - this->handleCollision(); + if (!lock) this->handleCollision(); - if (lock) - return; + if (lock) return; if (!actor->isTempAnimationPlaying()) { if (Vector2Equals(velocity, Vector2{0, 0})) { @@ -80,16 +80,23 @@ void Player::update() { void Player::draw() const { actor->draw(); - // debug draw interactable area.. - Color interactableAreaDebugColor = ORANGE; - interactableAreaDebugColor.a = (255 / 4); + bool debugDraw = true; - DrawRectangleRec(interactableArea, interactableAreaDebugColor); + if (Game::isUsingBin()) { + debugDraw = Game::getBin().gameSet.debugDraw; + } + + if (debugDraw) { + // debug draw interactable area.. + Color interactableAreaDebugColor = ORANGE; + interactableAreaDebugColor.a = (255 / 4); + + DrawRectangleRec(interactableArea, interactableAreaDebugColor); + } } void Player::handleCollision() { - if (actor == nullptr) - return; + if (actor == nullptr) return; Rectangle playerRect = actor->getCollisionRect(velocity); @@ -99,8 +106,7 @@ void Player::handleCollision() { // collision tiles for (auto &[pos, obj] : room.getCollisions().getObjects()) { Vector2 v = fromIVector(pos); - Rectangle tileRect = Rectangle{v.x * worldTileSize, v.y * worldTileSize, - static_cast(worldTileSize), + Rectangle tileRect = Rectangle{v.x * worldTileSize, v.y * worldTileSize, static_cast(worldTileSize), static_cast(worldTileSize)}; if (CheckCollisionRecs(playerRect, tileRect)) { @@ -117,15 +123,21 @@ void Player::handleCollision() { } } + // actors + for (auto &[name, actor] : room.getActors().getActors()) { + if (CheckCollisionRecs(playerRect, actor->getCollisionRect(Vector2{0, 0}))) { + velocity = Vector2{0, 0}; + break; + } + } + // interactable tiles - std::vector interactableTiles = - this->room.getInteractables().getList(); + std::vector interactableTiles = this->room.getInteractables().getList(); for (Interactable *interactable : interactableTiles) { Rectangle tileRect = Rectangle{interactable->getWorldPos().x * room.getWorldTileSize(), interactable->getWorldPos().y * room.getWorldTileSize(), - static_cast(room.getWorldTileSize()), - static_cast(room.getWorldTileSize())}; + static_cast(room.getWorldTileSize()), static_cast(room.getWorldTileSize())}; if (CheckCollisionRecs(playerRect, tileRect)) { velocity = Vector2{0, 0}; @@ -144,14 +156,12 @@ void Player::handleCollision() { } void Player::handleInteraction() { - std::vector interactableTiles = - this->room.getInteractables().getList(); + std::vector interactableTiles = this->room.getInteractables().getList(); for (Interactable *interactable : interactableTiles) { Rectangle tileRect = Rectangle{interactable->getWorldPos().x * room.getWorldTileSize(), interactable->getWorldPos().y * room.getWorldTileSize(), - static_cast(room.getWorldTileSize()), - static_cast(room.getWorldTileSize())}; + static_cast(room.getWorldTileSize()), static_cast(room.getWorldTileSize())}; if (CheckCollisionRecs(interactableArea, tileRect)) { if (interactable->getType() == "warper") { @@ -167,13 +177,21 @@ void Player::handleInteraction() { for (auto &[pos, prop] : room.getProps().getObjects()) { if (prop->getHasInteractable()) { - if (CheckCollisionRecs(interactableArea, - prop->getWorldCollisionRect())) { + if (CheckCollisionRecs(interactableArea, prop->getWorldCollisionRect())) { prop->getInteractable()->interact(); break; } } } + + for (auto &[name, actor] : room.getActors().getActors()) { + if (actor->hasInteractable()) { + if (CheckCollisionRecs(interactableArea, actor->getCollisionRect(Vector2{0, 0}))) { + actor->getInteractable()->interact(); + break; + } + } + } } void Player::setRoom(Room &room) const { @@ -190,8 +208,7 @@ void Player::moveByVelocity(Vector2 velocity) { } Vector2 Player::getPosition() const { - if (actor == nullptr) - return Vector2{0, 0}; + if (actor == nullptr) return Vector2{0, 0}; return actor->getPosition(); } @@ -202,29 +219,30 @@ void Player::setPosition(Vector2 pos) { } Vector2 Player::getCenterPosition() const { - if (actor == nullptr) - return Vector2{0, 0}; + if (actor == nullptr) return Vector2{0, 0}; Rectangle actorRect = actor->getRect(); - return Vector2{actorRect.x + (actorRect.width / 2), - actorRect.y + (actorRect.height / 2)}; + return Vector2{actorRect.x + (actorRect.width / 2), actorRect.y + (actorRect.height / 2)}; } Vector2 Player::getTilePosition() const { return actor->getTilePosition(); } void Player::setTilePosition(Vector2 tilePos) { if (!room.getTileMap()->worldPosIsValid(tilePos)) { - throw std::runtime_error(TextFormat( - "This world tile position does not exist: %i, %i", - static_cast(tilePos.x), static_cast(tilePos.y))); + throw std::runtime_error(TextFormat("This world tile position does not exist: %i, %i", + static_cast(tilePos.x), static_cast(tilePos.y))); } - actor->setTilePosition(tilePos, - room.getTileMap()->getTileSet()->getTileSize()); + actor->setTilePosition(tilePos, room.getTileMap()->getTileSet()->getTileSize()); } Vector2 Player::getCollisionPos() const { - if (actor == nullptr) - return Vector2{0, 0}; + if (actor == nullptr) return Vector2{0, 0}; + + return actor->getCollisionCenter(); +} + +Vector2 Player::getCollisionCenterPos() const { + if (actor == nullptr) return Vector2{0, 0}; return actor->getCollisionCenter(); } diff --git a/src/prop.cpp b/src/prop.cpp index 68841354..70faef1a 100644 --- a/src/prop.cpp +++ b/src/prop.cpp @@ -1,18 +1,19 @@ #include "prop.hpp" + +#include + +#include +#include +#include + #include "game.hpp" #include "gamedata.hpp" #include "interactable.hpp" #include "tilemap.hpp" -#include -#include -#include -#include using json = nlohmann::json; -Prop::Prop() - : worldPos(Vector2{}), tilePos(Vector2{}), atlasRect(), texture(), - collisionRect() {} +Prop::Prop() : worldPos(Vector2{}), tilePos(Vector2{}), atlasRect(), texture(), collisionRect() {} Prop::Prop(const std::string &filePath) { this->sourcePath = filePath; @@ -25,19 +26,15 @@ Prop::Prop(const std::string &filePath) { if (atlasRectVec.size() != 4) { throw std::runtime_error("Not enough items in atlas_rect."); } - this->atlasRect = Rectangle{static_cast(atlasRectVec[0]), - static_cast(atlasRectVec[1]), - static_cast(atlasRectVec[2]), - static_cast(atlasRectVec[3])}; + this->atlasRect = Rectangle{static_cast(atlasRectVec[0]), static_cast(atlasRectVec[1]), + static_cast(atlasRectVec[2]), static_cast(atlasRectVec[3])}; std::vector collisionRectVec = json.at("collision_rect"); if (collisionRectVec.size() != 4) { throw std::runtime_error("Not enough items in collision_rect."); } - this->collisionRect = Rectangle{static_cast(collisionRectVec[0]), - static_cast(collisionRectVec[1]), - static_cast(collisionRectVec[2]), - static_cast(collisionRectVec[3])}; + this->collisionRect = Rectangle{static_cast(collisionRectVec[0]), static_cast(collisionRectVec[1]), + static_cast(collisionRectVec[2]), static_cast(collisionRectVec[3])}; this->imagePath = json.at("image"); this->texture = LoadTexture(imagePath.c_str()); @@ -47,8 +44,7 @@ Prop::Prop(const std::string &filePath) { this->interactable = std::make_unique(); if (hasInteractable) { std::string intType = json.at("interactable_type"); - this->interactable = - std::make_unique(intType, tilePos, _RPGPP_TILESIZE); + this->interactable = std::make_unique(intType, tilePos, _RPGPP_TILESIZE); } UnloadFileText(jsonString); } @@ -67,39 +63,29 @@ Prop::Prop(PropBin bin) { this->sourcePath = bin.name; this->worldPos = Vector2{0, 0}; this->tilePos = Vector2{0, 0}; - this->atlasRect = Rectangle{static_cast(bin.atlasRect.x), - static_cast(bin.atlasRect.y), - static_cast(bin.atlasRect.width), - static_cast(bin.atlasRect.height)}; + this->atlasRect = Rectangle{static_cast(bin.atlasRect.x), static_cast(bin.atlasRect.y), + static_cast(bin.atlasRect.width), static_cast(bin.atlasRect.height)}; this->collisionRect = - Rectangle{static_cast(bin.collisionRect.x), - static_cast(bin.collisionRect.y), - static_cast(bin.collisionRect.width), - static_cast(bin.collisionRect.height)}; - - ImageBin imgBin = - Game::getBin().images.at(GetFileName(bin.imagePath.c_str())); - Image img = LoadImageFromMemory(GetFileExtension(bin.imagePath.c_str()), - imgBin.data.data(), imgBin.dataSize); + Rectangle{static_cast(bin.collisionRect.x), static_cast(bin.collisionRect.y), + static_cast(bin.collisionRect.width), static_cast(bin.collisionRect.height)}; + + ImageBin imgBin = Game::getBin().images.at(GetFileName(bin.imagePath.c_str())); + Image img = LoadImageFromMemory(GetFileExtension(bin.imagePath.c_str()), imgBin.data.data(), imgBin.dataSize); setTexture(LoadTextureFromImage(img)); UnloadImage(img); this->hasInteractable = bin.hasInteractable; this->interactable = std::make_unique(); if (hasInteractable) { - this->interactable = std::make_unique( - bin.intType, tilePos, _RPGPP_TILESIZE); + this->interactable = std::make_unique(bin.intType, tilePos, _RPGPP_TILESIZE); } } json Prop::dumpJson() { - std::vector atlasRectVec = { - static_cast(atlasRect.x), static_cast(atlasRect.y), - static_cast(atlasRect.width), static_cast(atlasRect.height)}; - std::vector collisionRectVec = { - static_cast(collisionRect.x), static_cast(collisionRect.y), - static_cast(collisionRect.width), - static_cast(collisionRect.height)}; + std::vector atlasRectVec = {static_cast(atlasRect.x), static_cast(atlasRect.y), + static_cast(atlasRect.width), static_cast(atlasRect.height)}; + std::vector collisionRectVec = {static_cast(collisionRect.x), static_cast(collisionRect.y), + static_cast(collisionRect.width), static_cast(collisionRect.height)}; json j{{"atlas_rect", atlasRectVec}, {"collision_rect", collisionRectVec}, @@ -111,9 +97,7 @@ json Prop::dumpJson() { std::string Prop::getSourcePath() const { return sourcePath; } -void Prop::setTexture(Texture2D texture_to_set) { - this->texture = texture_to_set; -} +void Prop::setTexture(Texture2D texture_to_set) { this->texture = texture_to_set; } Texture2D Prop::getTexture() const { return texture; } @@ -124,27 +108,20 @@ void Prop::setTextureFromPath(const std::string &image_path) { const char *Prop::getImagePath() const { return this->imagePath.c_str(); } -void Prop::setCollisionRect(Rectangle collision_rect_to_set) { - this->collisionRect = collision_rect_to_set; -} +void Prop::setCollisionRect(Rectangle collision_rect_to_set) { this->collisionRect = collision_rect_to_set; } void Prop::setWorldTilePos(Vector2 world_pos_to_set, int tileSize) { - this->worldPos = - Vector2{world_pos_to_set.x * tileSize, world_pos_to_set.y * tileSize}; + this->worldPos = Vector2{world_pos_to_set.x * tileSize, world_pos_to_set.y * tileSize}; this->tilePos = world_pos_to_set; } -void Prop::setWorldPos(Vector2 world_pos_to_set) { - this->worldPos = world_pos_to_set; -} +void Prop::setWorldPos(Vector2 world_pos_to_set) { this->worldPos = world_pos_to_set; } Vector2 Prop::getWorldPos() const { return worldPos; } Vector2 Prop::getWorldTilePos() const { return tilePos; } -void Prop::setAtlasRect(Rectangle atlas_rect_to_set) { - this->atlasRect = atlas_rect_to_set; -} +void Prop::setAtlasRect(Rectangle atlas_rect_to_set) { this->atlasRect = atlas_rect_to_set; } Rectangle Prop::getAtlasRect() const { return atlasRect; } @@ -153,8 +130,7 @@ Rectangle Prop::getCollisionRect() const { return collisionRect; } Rectangle Prop::getWorldCollisionRect() const { return Rectangle{worldPos.x + (collisionRect.x * RPGPP_DRAW_MULTIPLIER), worldPos.y + (collisionRect.y * RPGPP_DRAW_MULTIPLIER), - collisionRect.width * RPGPP_DRAW_MULTIPLIER, - collisionRect.height * RPGPP_DRAW_MULTIPLIER}; + collisionRect.width * RPGPP_DRAW_MULTIPLIER, collisionRect.height * RPGPP_DRAW_MULTIPLIER}; } Vector2 Prop::getCollisionCenter() const { @@ -173,9 +149,7 @@ Interactable *Prop::getInteractable() const { } } -std::string Prop::getInteractableType() const { - return interactable->getType(); -} +std::string Prop::getInteractableType() const { return interactable->getType(); } void Prop::setInteractableType(const std::string &type) { if (hasInteractable && interactable->getType() == type) { @@ -186,10 +160,17 @@ void Prop::setInteractableType(const std::string &type) { } void Prop::draw() const { - Rectangle dest = {worldPos.x, worldPos.y, - atlasRect.width * RPGPP_DRAW_MULTIPLIER, + Rectangle dest = {worldPos.x, worldPos.y, atlasRect.width * RPGPP_DRAW_MULTIPLIER, atlasRect.height * RPGPP_DRAW_MULTIPLIER}; DrawTexturePro(texture, atlasRect, dest, Vector2{0, 0}, 0.0f, WHITE); - DrawRectangleRec(getWorldCollisionRect(), Fade(RED, 0.5f)); + bool debugDraw = true; + + if (Game::isUsingBin()) { + debugDraw = Game::getBin().gameSet.debugDraw; + } + + if (debugDraw) { + DrawRectangleRec(getWorldCollisionRect(), Fade(RED, 0.5f)); + } } diff --git a/src/propsContainer.cpp b/src/propsContainer.cpp index 3d9551e4..4719c429 100644 --- a/src/propsContainer.cpp +++ b/src/propsContainer.cpp @@ -1,4 +1,5 @@ #include "propsContainer.hpp" + #include "conversion.hpp" #include "game.hpp" #include "prop.hpp" @@ -8,8 +9,7 @@ void PropsContainer::addProp(Vector2 pos, const std::string &type) { if (propBin.name == type) { printf("c \n"); auto p = std::make_unique(propBin); - p->setWorldTilePos(pos, - Game::getWorld().getRoom().getWorldTileSize()); + p->setWorldTilePos(pos, Game::getWorld().getRoom().getWorldTileSize()); p->getInteractable()->setProps(nlohmann::json::object()); pushObject(fromVector2(pos), std::move(p)); @@ -18,6 +18,4 @@ void PropsContainer::addProp(Vector2 pos, const std::string &type) { } } -Prop *PropsContainer::getPropAt(Vector2 pos) { - return objects[fromVector2(pos)].get(); -} \ No newline at end of file +Prop *PropsContainer::getPropAt(Vector2 pos) { return objects[fromVector2(pos)].get(); } \ No newline at end of file diff --git a/src/resourceService.cpp b/src/resourceService.cpp index 3a0afb70..9655640f 100644 --- a/src/resourceService.cpp +++ b/src/resourceService.cpp @@ -1,13 +1,54 @@ #include "resourceService.hpp" -#include + #include -ResourceService::ResourceService() { - addTextureFromFile("resources/logo.png"); - addTextureFromFile("resources/close.png"); - addTextureFromFile("resources/cross.png"); - addTextureFromFile("resources/dialog.png"); - addTextureFromFile("resources/figurine.png"); +#include + +#include "game.hpp" + +ResourceService::ResourceService() { init(); } + +void ResourceService::init() { + unload(); + + if (Game::isUsingBin()) { + for (auto &[id, fontBin] : Game::getBin().fonts) { + Font font = LoadFontFromMemory(fontBin.ext.c_str(), fontBin.data.data(), fontBin.dataSize, 13, nullptr, 0); + addFont(id, font); + + // font sizes, defined in the project settings + for (int fontSize : Game::getBin().gameSet.exportFontSizes) { + Font font = LoadFontFromMemory(fontBin.ext.c_str(), fontBin.data.data(), fontBin.dataSize, fontSize, + nullptr, 0); + addFont(TextFormat("%s-%i", id.c_str(), fontSize), font); + } + } + + for (const auto &[name, data] : Game::getBin().images) { + // scale 1 - the image as it is + Image image = LoadImageFromMemory(data.ext.c_str(), data.data.data(), data.dataSize); + Texture2D texture = LoadTextureFromImage(image); + addTexture(name, texture); + UnloadImage(image); + + // scales, defined in the settings of the project + for (int imageScale : Game::getBin().gameSet.exportImageScales) { + if (imageScale > 1) { + Image image = LoadImageFromMemory(data.ext.c_str(), data.data.data(), data.dataSize); + ImageResize(&image, image.width * imageScale, image.height * imageScale); + Texture2D texture = LoadTextureFromImage(image); + addTexture(TextFormat("%s-%i", name.c_str(), imageScale), texture); + UnloadImage(image); + } + } + } + } else { + auto dirList = LoadDirectoryFiles("fonts/"); + for (int i = 0; i < dirList.count; i++) { + auto path = dirList.paths[i]; + addFontFromFile(path, 13); + } + } } ResourceService::~ResourceService() = default; @@ -23,12 +64,27 @@ void ResourceService::addTextureFromFile(const std::string &filePath) { addTexture(newId, text); } +Texture2D ResourceService::getTexture(const std::string &id) { return textures[id]; } + +void ResourceService::addFont(const std::string &id, Font font) { fonts[id] = font; } + +void ResourceService::addFontFromFile(const std::string &filePath, int fontSize) { + Font font = LoadFontEx(filePath.c_str(), fontSize, nullptr, 250); + addFont(GetFileNameWithoutExt(filePath.c_str()), font); +} + +Font ResourceService::getFont(const std::string &id) { return fonts.at(id); } + void ResourceService::unload() const { for (const auto &[name, texture] : textures) { - UnloadTexture(texture); + if (IsTextureValid(texture)) { + UnloadTexture(texture); + } } -} -Texture2D ResourceService::getTexture(const std::string &id) { - return textures[id]; + for (const auto &[id, font] : fonts) { + if (IsFontValid(font)) { + UnloadFont(font); + } + } } diff --git a/src/room.cpp b/src/room.cpp index 170c8d8e..cc936004 100644 --- a/src/room.cpp +++ b/src/room.cpp @@ -1,4 +1,14 @@ #include "room.hpp" + +#include + +#include +#include +#include +#include +#include +#include + #include "actor.hpp" #include "actorContainer.hpp" #include "collisionsContainer.hpp" @@ -10,13 +20,6 @@ #include "prop.hpp" #include "propsContainer.hpp" #include "tilemap.hpp" -#include -#include -#include -#include -#include -#include -#include using json = nlohmann::json; @@ -40,7 +43,7 @@ Room::Room() { this->player = std::unique_ptr{}; } -Room::Room(const std::string &fileName, int tileSize) { +Room::Room(const std::string &fileName, int tileSize, bool createPlayer) { this->lock = false; Camera2D initialCamera; @@ -58,21 +61,21 @@ Room::Room(const std::string &fileName, int tileSize) { UnloadFileText(jsonString); std::vector startPosVec = roomJson.at("start_pos"); - startTile = Vector2{static_cast(startPosVec[0]), - static_cast(startPosVec[1])}; + startTile = Vector2{static_cast(startPosVec[0]), static_cast(startPosVec[1])}; this->interactables = std::make_unique(); this->collisions = std::make_unique(); this->actors = std::make_unique(); this->props = std::make_unique(); - this->tileMap = std::make_unique(fileName); - auto actor = std::make_unique(DEFAULT_PLAYER_PATH); - actor->setTilePosition(Vector2{startTile.x, startTile.y}, - tileMap->getTileSet()->getTileSize()); - auto initialPlayer = std::make_unique(std::move(actor), *this); - this->addPlayer(std::move(initialPlayer)); + if (createPlayer) { + auto actor = std::make_unique(DEFAULT_PLAYER_PATH); + actor->setTilePosition(Vector2{startTile.x, startTile.y}, tileMap->getTileSet()->getTileSize()); + auto initialPlayer = std::make_unique(std::move(actor), *this); + + this->addPlayer(std::move(initialPlayer)); + } std::vector> collisionsVec = roomJson.at("collision"); for (auto v : collisionsVec) { @@ -82,21 +85,17 @@ Room::Room(const std::string &fileName, int tileSize) { collisions->pushObject({x, y}, false); } - std::map> propsVec = - roomJson.at("props"); + std::map> propsVec = roomJson.at("props"); for (auto const &[key, value] : propsVec) { int count = 0; char **textSplit = TextSplit(key.c_str(), ';', &count); - if (count != 2) - return; + if (count != 2) return; int x = std::stoi(std::string(textSplit[0])); int y = std::stoi(std::string(textSplit[1])); auto propVec = value; auto p = std::make_unique(propVec.at("src")); - p->setWorldTilePos( - Vector2{static_cast(x), static_cast(y)}, - worldTileSize); + p->setWorldTilePos(Vector2{static_cast(x), static_cast(y)}, worldTileSize); p->getInteractable()->setProps(propVec.at("props")); @@ -107,15 +106,23 @@ Room::Room(const std::string &fileName, int tileSize) { for (auto const &[key, value] : actorsVec) { int count = 0; char **textSplit = TextSplit(key.c_str(), ';', &count); - if (count != 2) - return; + if (count != 2) return; int x = std::stoi(std::string(textSplit[0])); int y = std::stoi(std::string(textSplit[1])); auto a = std::make_unique(value.at("source")); - a->setTilePosition( - Vector2{static_cast(x), static_cast(y)}, - tileMap->getTileSet()->getTileSize()); + a->setTilePosition(Vector2{static_cast(x), static_cast(y)}, tileMap->getTileSet()->getTileSize()); + + std::string intType = value.at("intType"); + + if (intType.empty()) { + a->setHasInteractable(false); + } else { + a->setHasInteractable(true); + a->getInteractable()->setType(intType); + a->getInteractable()->setProps(value.at("props")); + } + actors->getActors()[value.at("name")] = std::move(a); } @@ -124,9 +131,7 @@ Room::Room(const std::string &fileName, int tileSize) { musicSource = roomJson.at("music_source"); } -Room::Room(std::unique_ptr tileMap) : Room() { - this->tileMap = std::move(tileMap); -} +Room::Room(std::unique_ptr tileMap) : Room() { this->tileMap = std::move(tileMap); } Room::Room(const RoomBin &bin) : Room() { this->worldTileSize = 48; @@ -138,11 +143,17 @@ Room::Room(const RoomBin &bin) : Room() { this->tileMap = std::make_unique(bin); - auto &actorBin = Game::getBin().actors["playerActor"]; + ActorBin actorBin; + + if (Game::getBin().gameSet.playerActorPath.empty()) { + actorBin = Game::getBin().actors["playerActor"]; + } else { + std::string playerActorName = GetFileNameWithoutExt(Game::getBin().gameSet.playerActorPath.c_str()); + actorBin = Game::getBin().actors[playerActorName]; + } auto actor = std::make_unique(actorBin); - actor->setTilePosition(Vector2{static_cast(bin.startPoint.x), - static_cast(bin.startPoint.y)}, + actor->setTilePosition(Vector2{static_cast(bin.startPoint.x), static_cast(bin.startPoint.y)}, tileMap->getTileSet()->getTileSize()); printf("%s \n", actor->getSourcePath().c_str()); auto initialPlayer = std::make_unique(std::move(actor), *this); @@ -157,20 +168,13 @@ Room::Room(const RoomBin &bin) : Room() { for (auto const &propSource : bin.props) { for (auto const &propBin : Game::getBin().props) { - std::string actualSource = - GetFileNameWithoutExt(propSource.name.c_str()); - printf("%s ; %s \n", propBin.name.c_str(), actualSource.c_str()); + std::string actualSource = GetFileNameWithoutExt(propSource.name.c_str()); if (propBin.name == actualSource) { - printf("c \n"); auto p = std::make_unique(propBin); p->setWorldTilePos( - Vector2{static_cast(propSource.tilePos.x), - static_cast(propSource.tilePos.y)}, + Vector2{static_cast(propSource.tilePos.x), static_cast(propSource.tilePos.y)}, worldTileSize); - p->getInteractable()->setProps( - nlohmann::json::from_cbor(propSource.propsCbor)); - - // addProp(std::move(*p)); + p->getInteractable()->setProps(nlohmann::json::from_cbor(propSource.propsCbor)); props->pushObject(propSource.tilePos, std::move(p)); break; @@ -180,14 +184,17 @@ Room::Room(const RoomBin &bin) : Room() { for (const auto &actorSource : bin.actors) { for (const auto [name, actorBin] : Game::getBin().actors) { - std::string sourceFileName = - GetFileName(actorSource.source.c_str()); + std::string sourceFileName = GetFileName(actorSource.source.c_str()); if (actorBin.name == sourceFileName) { auto a = std::make_unique(actorBin); a->setTilePosition( - Vector2{static_cast(actorSource.tilePos.x), - static_cast(actorSource.tilePos.y)}, + Vector2{static_cast(actorSource.tilePos.x), static_cast(actorSource.tilePos.y)}, tileMap->getTileSet()->getTileSize()); + if (!actorSource.intType.empty()) { + a->setHasInteractable(true); + a->getInteractable()->setType(actorSource.intType); + a->getInteractable()->setProps(nlohmann::json::from_cbor(actorSource.propsCbor)); + } actors->getActors()[actorSource.name] = std::move(a); break; } @@ -224,13 +231,11 @@ json Room::dumpJson() { auto propsMap = std::map{}; for (auto &[pos, prop] : props->getObjects()) { - std::string key = - TextFormat("%i;%i", static_cast(prop->getWorldTilePos().x), - static_cast(prop->getWorldTilePos().y)); + std::string key = TextFormat("%i;%i", static_cast(prop->getWorldTilePos().x), + static_cast(prop->getWorldTilePos().y)); auto propJson = json::object(); - propJson["src"] = - TextFormat("props/%s", GetFileName(prop->getSourcePath().c_str())); + propJson["src"] = TextFormat("props/%s", GetFileName(prop->getSourcePath().c_str())); if (prop->getHasInteractable()) { propJson["props"] = prop->getInteractable()->getProps(); @@ -244,13 +249,18 @@ json Room::dumpJson() { auto actorsMap = std::map{}; for (auto &[name, obj] : actors->getActors()) { std::string key = - TextFormat("%i;%i", static_cast(obj->getTilePosition().x), - static_cast(obj->getTilePosition().y)); + TextFormat("%i;%i", static_cast(obj->getTilePosition().x), static_cast(obj->getTilePosition().y)); auto actorInfo = std::map{}; - actorInfo["source"] = - TextFormat("actors/%s", GetFileName(obj->getSourcePath().c_str())); + actorInfo["source"] = TextFormat("actors/%s", GetFileName(obj->getSourcePath().c_str())); actorInfo["name"] = name; + if (obj->hasInteractable()) { + actorInfo["intType"] = obj->getInteractable()->getType(); + actorInfo["props"] = obj->getInteractable()->getProps(); + } else { + actorInfo["intType"] = ""; + actorInfo["props"] = json::object(); + } actorsMap[key] = actorInfo; } @@ -259,9 +269,7 @@ json Room::dumpJson() { roomJson.push_back({"props", propsMap}); roomJson.push_back({"actors", actorsMap}); roomJson.push_back({"music_source", musicSource}); - roomJson.push_back( - {"start_pos", - {static_cast(startTile.x), static_cast(startTile.y)}}); + roomJson.push_back({"start_pos", {static_cast(startTile.x), static_cast(startTile.y)}}); return roomJson; } @@ -281,8 +289,7 @@ void Room::update() { actor->update(); } player->update(); - if (!lock) - updateCamera(); + if (!lock) updateCamera(); } void Room::updateCamera() { @@ -306,38 +313,51 @@ void Room::draw() const { BeginMode2D(camera); this->tileMap->draw(); - for (auto i : interactables->getList()) { - auto rect = Rectangle{ - i->getWorldPos().x * static_cast(getWorldTileSize()), - i->getWorldPos().y * static_cast(getWorldTileSize()), - static_cast(getWorldTileSize()), - static_cast(getWorldTileSize())}; - DrawRectangleRec(rect, Fade(YELLOW, 0.5f)); + + bool debugDraw = true; + + if (Game::isUsingBin()) { + debugDraw = Game::getBin().gameSet.debugDraw; } - for (auto &[vect, value] : collisions->getObjects()) { - auto rect = Rectangle{vect.x * static_cast(worldTileSize), - vect.y * static_cast(worldTileSize), - static_cast(worldTileSize), - static_cast(worldTileSize)}; - DrawRectangleRec(rect, Fade(RED, 0.5f)); + + if (debugDraw) { + for (auto i : interactables->getList()) { + auto rect = Rectangle{i->getWorldPos().x * static_cast(getWorldTileSize()), + i->getWorldPos().y * static_cast(getWorldTileSize()), + static_cast(getWorldTileSize()), static_cast(getWorldTileSize())}; + DrawRectangleRec(rect, Fade(YELLOW, 0.5f)); + } + for (auto &[vect, value] : collisions->getObjects()) { + auto rect = + Rectangle{vect.x * static_cast(worldTileSize), vect.y * static_cast(worldTileSize), + static_cast(worldTileSize), static_cast(worldTileSize)}; + DrawRectangleRec(rect, Fade(RED, 0.5f)); + } } for (auto &[pos, prop] : props->getObjects()) { - if (prop->getCollisionCenter().y <= player->getCollisionPos().y) { + if (prop->getCollisionCenter().y <= player->getCollisionCenterPos().y) { prop->draw(); } } - - for (auto &[vect, actor] : actors->getActors()) { - actor->draw(); + for (auto &[name, actor] : actors->getActors()) { + if (actor->getCollisionCenter().y <= player->getCollisionCenterPos().y) { + actor->draw(); + } } + player->draw(); for (auto &[pos, prop] : props->getObjects()) { - if (prop->getCollisionCenter().y > player->getCollisionPos().y) { + if (prop->getCollisionCenter().y > player->getCollisionCenterPos().y) { prop->draw(); } } + for (auto &[name, actor] : actors->getActors()) { + if (actor->getCollisionCenter().y > player->getCollisionCenterPos().y) { + actor->draw(); + } + } EndMode2D(); } @@ -348,9 +368,7 @@ int Room::getWorldTileSize() const { return worldTileSize; } void Room::setLock(bool val) { this->lock = val; } -void Room::addPlayer(std::unique_ptr newPlayer) { - this->player = std::move(newPlayer); -} +void Room::addPlayer(std::unique_ptr newPlayer) { this->player = std::move(newPlayer); } Player &Room::getPlayer() const { return *player; } @@ -360,21 +378,15 @@ void Room::setTileMap(TileMap *newTileMap) { tileMap.reset(newTileMap); } std::string Room::getMusicSource() const { return musicSource; } -void Room::setMusicSource(const std::string_view &newMusicSource) { - this->musicSource = newMusicSource; -} +void Room::setMusicSource(const std::string_view &newMusicSource) { this->musicSource = newMusicSource; } Vector2 Room::getStartTile() const { return startTile; } -void Room::setStartTile(Vector2 newStartTile) { - this->startTile = newStartTile; -} +void Room::setStartTile(Vector2 newStartTile) { this->startTile = newStartTile; } CollisionsContainer &Room::getCollisions() const { return *this->collisions; } -InteractablesContainer &Room::getInteractables() const { - return *this->interactables; -} +InteractablesContainer &Room::getInteractables() const { return *this->interactables; } PropsContainer &Room::getProps() const { return *this->props; } diff --git a/src/rpgpplua/rpgpplua.cpp b/src/rpgpplua/rpgpplua.cpp index 8e3c0bc3..c3860970 100644 --- a/src/rpgpplua/rpgpplua.cpp +++ b/src/rpgpplua/rpgpplua.cpp @@ -1,17 +1,17 @@ -#include "game.hpp" -#include "gamedata.hpp" -#include #include + +#include #include #include #include #include +#include "game.hpp" +#include "gamedata.hpp" + void printer() { printf("man\n"); } -void draw_text_lua(const char *text, int posX, int posY, int fontSize) { - DrawText(text, posX, posY, fontSize, BLACK); -} +void draw_text_lua(const char *text, int posX, int posY, int fontSize) { DrawText(text, posX, posY, fontSize, BLACK); } void clear_bg_lua() { ClearBackground(RAYWHITE); } @@ -35,8 +35,7 @@ extern "C" lua.set_function("clear_background", &clear_bg_lua); lua.set_function("draw_text", draw_text_lua); - sol::usertype game_type = - lua.new_usertype("game", sol::constructors()); + sol::usertype game_type = lua.new_usertype("game", sol::constructors()); game_type["init"] = &Game::init; game_type["use_bin"] = &Game::useBin; diff --git a/src/scriptFile.cpp b/src/scriptFile.cpp index 76175a11..90f10bdb 100644 --- a/src/scriptFile.cpp +++ b/src/scriptFile.cpp @@ -1,13 +1,11 @@ #include "scriptFile.h" -#include "raylib.h" - #include -ScriptFile::ScriptFile(const std::string &path) { - this->fileContents = LoadFileText(path.c_str()); -} +#include "raylib.h" + +ScriptFile::ScriptFile(const std::string &path) { this->fileContents = LoadFileText(path.c_str()); } nlohmann::json ScriptFile::dumpJson() { return nlohmann::json{}; } diff --git a/src/scriptService.cpp b/src/scriptService.cpp index 1f6ae0ea..937b9a59 100644 --- a/src/scriptService.cpp +++ b/src/scriptService.cpp @@ -1,34 +1,33 @@ #include "scriptService.hpp" + +#include +#include + #include "lua/apiTypes.hpp" #include "lua/interfaceApi.hpp" #include "lua/soundsApi.hpp" #include "lua/stateApi.hpp" #include "lua/worldApi.hpp" #include "sol/state_view.hpp" - #include "sol/table.hpp" -#include -#include static int wrap_exceptions(lua_State *L, lua_CFunction f) { try { - return f(L); // Call wrapped function and return result. - } catch (const char *s) { // Catch and convert exceptions. + return f(L); // Call wrapped function and return result. + } catch (const char *s) { // Catch and convert exceptions. lua_pushstring(L, s); } catch (std::exception &e) { lua_pushstring(L, e.what()); } catch (...) { lua_pushliteral(L, "caught (...)"); } - return lua_error(L); // Rethrow as a Lua error. + return lua_error(L); // Rethrow as a Lua error. } ScriptService::ScriptService() { - state.open_libraries(sol::lib::base, sol::lib::string, sol::lib::os, - sol::lib::table); + state.open_libraries(sol::lib::base, sol::lib::string, sol::lib::os, sol::lib::table); lua_pushlightuserdata(state.lua_state(), (void *)wrap_exceptions); - luaJIT_setmode(state.lua_state(), -1, - LUAJIT_MODE_WRAPCFUNC | LUAJIT_MODE_ON); + luaJIT_setmode(state.lua_state(), -1, LUAJIT_MODE_WRAPCFUNC | LUAJIT_MODE_ON); lua_pop(state.lua_state(), 1); setLua(state); } diff --git a/src/soundService.cpp b/src/soundService.cpp index ce7f3768..dc4e1a3f 100644 --- a/src/soundService.cpp +++ b/src/soundService.cpp @@ -1,10 +1,13 @@ #include "soundService.hpp" -#include "game.hpp" -#include "gamedata.hpp" -#include + #include + +#include #include +#include "game.hpp" +#include "gamedata.hpp" + SoundService::SoundService() { music = {}; musicLoaded = false; @@ -14,18 +17,15 @@ SoundService::SoundService() { bool SoundService::loadMusic(const std::string &id) { GameData &gameData = Game::getBin(); - if (lastId == id) - return true; + if (lastId == id) return true; if (gameData.music.count(id) != 0) { - if (gameData.music[id].isSound) - return musicLoaded; + if (gameData.music[id].isSound) return musicLoaded; auto &musicBin = gameData.music[id]; - Music newMusic = LoadMusicStreamFromMemory(musicBin.fileExt.c_str(), - musicBin.fileData.data(), - musicBin.fileData.size()); + Music newMusic = + LoadMusicStreamFromMemory(musicBin.fileExt.c_str(), musicBin.fileData.data(), musicBin.fileData.size()); if (IsMusicValid(newMusic)) { unload(); @@ -52,9 +52,8 @@ void SoundService::playSound(const std::string &id) const { if (gameData.music.count(id) != 0) { if (gameData.music[id].isSound) { MusicBin soundBin = gameData.music[id]; - Wave soundWave = LoadWaveFromMemory(soundBin.fileExt.c_str(), - soundBin.fileData.data(), - soundBin.fileData.size()); + Wave soundWave = + LoadWaveFromMemory(soundBin.fileExt.c_str(), soundBin.fileData.data(), soundBin.fileData.size()); Sound sound = LoadSoundFromWave(soundWave); PlaySound(sound); @@ -64,8 +63,7 @@ void SoundService::playSound(const std::string &id) const { // UnloadSound(sound); } } else { - throw std::runtime_error( - TextFormat("This Sound does not exist: %s", id.c_str())); + throw std::runtime_error(TextFormat("This Sound does not exist: %s", id.c_str())); } } diff --git a/src/stateService.cpp b/src/stateService.cpp index e29dafbe..b5d1c123 100644 --- a/src/stateService.cpp +++ b/src/stateService.cpp @@ -1,11 +1,10 @@ #include "stateService.hpp" + #include "sol/error.hpp" StateService::StateService() { gameState.emplace("test", false); } -void StateService::setProp(const std::string &prop, Value value) { - gameState[prop] = value; -} +void StateService::setProp(const std::string &prop, Value value) { gameState[prop] = value; } Value StateService::getProp(const std::string &prop) const { if (gameState.count(prop) == 0) { diff --git a/src/textArea.cpp b/src/textArea.cpp index c7f870b4..ab455d58 100644 --- a/src/textArea.cpp +++ b/src/textArea.cpp @@ -1,7 +1,9 @@ #include "textArea.hpp" -#include "game.hpp" + #include +#include "game.hpp" + TextArea::TextArea() : rect(Rectangle{}) {} TextArea::TextArea(Rectangle rect) { @@ -24,12 +26,10 @@ void TextArea::draw() { void TextArea::putChar(int i, Vector2 *charPos, Vector2 *charMeasure) const { charPos->x += charMeasure->x; - DrawTextPro(Game::getUi().getFont(), TextSubtext(content.c_str(), i, 1), - *charPos, Vector2{0, 0}, 0.0f, 13 * 3, 1, BLACK); + DrawTextPro(Game::getUi().getFont(), TextSubtext(content.c_str(), i, 1), *charPos, Vector2{0, 0}, 0.0f, 13 * 3, 1, + BLACK); - *charMeasure = - MeasureTextEx(Game::getUi().getFont(), - TextSubtext(content.c_str(), i, 1), 13 * 3, 1.0f); + *charMeasure = MeasureTextEx(Game::getUi().getFont(), TextSubtext(content.c_str(), i, 1), 13 * 3, 1.0f); } void TextArea::setText(const std::string &text) { this->content = text; } diff --git a/src/tile.cpp b/src/tile.cpp index d8e6395f..1a69f27e 100644 --- a/src/tile.cpp +++ b/src/tile.cpp @@ -1,7 +1,9 @@ #include "tile.hpp" -#include "atlasTile.hpp" + #include +#include "atlasTile.hpp" + Tile::Tile() { this->worldCoords = Vector2{-1, -1}; this->placed = false; diff --git a/src/winapi.cpp b/src/winapi.cpp index f61b3ce7..2680d322 100644 --- a/src/winapi.cpp +++ b/src/winapi.cpp @@ -1,39 +1,53 @@ +#include #include - #include #ifdef _WIN32 -#include #include -#include -#include - #endif #ifdef _WIN32 char *WinReadFromHandle(HANDLE handle) { DWORD dwRead; - CHAR charBuf[4096]; + char *charBuf = new char[4096]; BOOL bSuccess = FALSE; for (;;) { bSuccess = ReadFile(handle, charBuf, 4096, &dwRead, NULL); - if (!bSuccess || dwRead == 0) - break; + if (!bSuccess || dwRead == 0) break; - if (!bSuccess) - break; + if (!bSuccess) break; } return charBuf; } +bool WinCreateDetachedExecutable(std::string path) { + BOOL creationResult; + STARTUPINFO startupInfo; + PROCESS_INFORMATION processInformation; + + ZeroMemory(&startupInfo, sizeof(startupInfo)); + startupInfo.cb = sizeof(startupInfo); + ZeroMemory(&processInformation, sizeof(processInformation)); + + creationResult = CreateProcess(NULL, path.data(), NULL, NULL, FALSE, + CREATE_NEW_CONSOLE | CREATE_NEW_PROCESS_GROUP | CREATE_BREAKAWAY_FROM_JOB, NULL, + NULL, &startupInfo, &processInformation); + + if (creationResult) { + CloseHandle(processInformation.hProcess); + CloseHandle(processInformation.hThread); + } + + return creationResult; +} + bool WinOpenFileAssociate(std::string operation, std::string file) { printf("opening file with path %s (Win32)\n", file.c_str()); - INT_PTR hInstance = (INT_PTR)ShellExecuteA( - NULL, operation.c_str(), file.c_str(), NULL, NULL, SW_SHOWNORMAL); + INT_PTR hInstance = (INT_PTR)ShellExecuteA(NULL, operation.c_str(), file.c_str(), NULL, NULL, SW_SHOWNORMAL); return hInstance != SE_ERR_NOASSOC; } @@ -42,8 +56,7 @@ void WinWriteToHandle(HANDLE handle, std::string str) { CHAR charBuf[4096]; BOOL bSuccess = FALSE; - bSuccess = WriteFile(handle, static_cast(str.data()), str.size(), - &dwWritten, NULL); + bSuccess = WriteFile(handle, static_cast(str.data()), str.size(), &dwWritten, NULL); if (!bSuccess) { printf("WriteFile Error: %lu", GetLastError()); return; @@ -54,8 +67,36 @@ void WinWriteToHandle(HANDLE handle, std::string str) { } } -void WinCreateProcEx(std::string cmdLine, HANDLE outHandle, HANDLE inHandle, - DWORD dwFlags, bool wait) { +void WinRunWithLog(std::string logName, std::string cmdLine) { + HANDLE outFile = nullptr; + + outFile = + CreateFile(logName.c_str(), GENERIC_WRITE, FILE_SHARE_WRITE, NULL, OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL); + + PROCESS_INFORMATION piProcInfo; + STARTUPINFO siStartInfo; + + SetStdHandle(STD_OUTPUT_HANDLE, outFile); + ZeroMemory(&piProcInfo, sizeof(PROCESS_INFORMATION)); + + ZeroMemory(&siStartInfo, sizeof(STARTUPINFO)); + siStartInfo.cb = sizeof(STARTUPINFO); + siStartInfo.hStdOutput = outFile; + siStartInfo.dwFlags |= STARTF_USESTDHANDLES; + + bool success = CreateProcess(NULL, cmdLine.data(), NULL, NULL, true, 0, NULL, NULL, &siStartInfo, &piProcInfo); + + if (!success) { + printf("Child process doesn't work. \n"); + } else { + CloseHandle(piProcInfo.hProcess); + CloseHandle(piProcInfo.hThread); + + CloseHandle(outFile); + } +} + +void WinCreateProcEx(std::string cmdLine, HANDLE outHandle, HANDLE inHandle, DWORD dwFlags, bool wait) { #ifdef _WIN32 STARTUPINFO si; PROCESS_INFORMATION pi; @@ -77,8 +118,8 @@ void WinCreateProcEx(std::string cmdLine, HANDLE outHandle, HANDLE inHandle, handleInheritance = TRUE; } - if (CreateProcess(NULL, const_cast(cmdLine.data()), NULL, NULL, - handleInheritance, 0, NULL, NULL, &si, &pi)) { + if (CreateProcess(NULL, const_cast(cmdLine.data()), NULL, NULL, handleInheritance, 0, NULL, NULL, &si, + &pi)) { // Wait until child process exits. if (wait) { WaitForSingleObject(pi.hProcess, INFINITE); @@ -88,10 +129,8 @@ void WinCreateProcEx(std::string cmdLine, HANDLE outHandle, HANDLE inHandle, CloseHandle(pi.hProcess); CloseHandle(pi.hThread); - if (outHandle != NULL) - CloseHandle(outHandle); - if (inHandle != NULL) - CloseHandle(inHandle); + if (outHandle != NULL) CloseHandle(outHandle); + if (inHandle != NULL) CloseHandle(inHandle); } else { printf("WinCreateProc: CreateProcess failed (%lu).\n", GetLastError()); } @@ -100,9 +139,7 @@ void WinCreateProcEx(std::string cmdLine, HANDLE outHandle, HANDLE inHandle, #endif } -void WinCreateProc(std::string cmdLine) { - WinCreateProcEx(cmdLine, NULL, NULL, STARTF_FORCEONFEEDBACK, true); -} +void WinCreateProc(std::string cmdLine) { WinCreateProcEx(cmdLine, NULL, NULL, STARTF_FORCEONFEEDBACK, true); } VsInfo WinVsWhere(std::string path) { VsInfo result; @@ -140,8 +177,7 @@ VsInfo WinVsWhere(std::string path) { return result; } - WinCreateProcEx(path, g_hChildStd_OUT_Wr, NULL, STARTF_USESTDHANDLES, - false); + WinCreateProcEx(path, g_hChildStd_OUT_Wr, NULL, STARTF_USESTDHANDLES, false); CHAR *charBuf = WinReadFromHandle(g_hChildStd_OUT_Rd); std::string bufferString = charBuf; diff --git a/src/worldService.cpp b/src/worldService.cpp index 846f069f..12c8a7f4 100644 --- a/src/worldService.cpp +++ b/src/worldService.cpp @@ -1,9 +1,11 @@ #include "worldService.hpp" -#include "game.hpp" -#include "room.hpp" + #include #include +#include "game.hpp" +#include "room.hpp" + WorldService::WorldService() { this->lock = false; this->room = std::unique_ptr{}; @@ -22,9 +24,7 @@ void WorldService::setRoom(const std::string_view &filePath) { this->room = std::make_unique(std::string(filePath)); } -void WorldService::setRoomBin(RoomBin bin) { - this->room = std::make_unique(bin); -} +void WorldService::setRoomBin(RoomBin bin) { this->room = std::make_unique(bin); } void WorldService::setRoomBin(const std::string &roomBin) { for (RoomBin bin : Game::getBin().rooms) { @@ -89,8 +89,7 @@ void WorldService::draw() const { room->draw(); if (transitionActive) { - DrawRectangleRec(Rectangle{0, 0, static_cast(GetScreenWidth()), - static_cast(GetScreenHeight())}, + DrawRectangleRec(Rectangle{0, 0, static_cast(GetScreenWidth()), static_cast(GetScreenHeight())}, transitionColor); } } diff --git a/tools/translation_checker/checker.lua b/tools/translation_checker/checker.lua index e40ff711..9130858e 100644 --- a/tools/translation_checker/checker.lua +++ b/tools/translation_checker/checker.lua @@ -60,36 +60,36 @@ local function _CompareTranslation(base, target, filename) local translatedCnt = tableLength(base) - tableLength(missing) - tableLength(untranslated) local percent = translatedCnt / tableLength(base) * 100 - print("\n" .. "===" .. filename .. "===") - print("Completion: " .. percent .. "%") + print("\n" .. target["language"] .. " (" .. filename .. ")\n" .. "--------") + print("Completion: " .. string.format("%.2f", percent) .. "%") table.sort(missing) table.sort(extra) table.sort(untranslated) if #missing ~= 0 then - print("\n" .. "Missing keys (should be added):") + print("Missing keys (should be added):") for _, k in ipairs(missing) do print(" - " .. k) end end if #untranslated ~= 0 then - print("\n" .. "Untranslated keys (same as base):") + print("Untranslated keys (same as base):") for _, k in ipairs(untranslated) do print(" - " .. k) end end if #extra ~= 0 then - print("\n" .. "Extra keys (should be removed):") + print("Extra keys (should be removed):") for _, k in ipairs(extra) do print(" - " .. k) end end if #missing == 0 and #untranslated == 0 and #extra == 0 then - print("\n" .. "Translation is up to date!") + print("Translation is up to date!") end end diff --git a/xmake.lua b/xmake.lua index d27cbe7d..bd89ee14 100644 --- a/xmake.lua +++ b/xmake.lua @@ -20,37 +20,6 @@ on_install("linux", "macosx", "mingw", "windows", function (package) end) package_end() -package("noop") -set_sourcedir(path.join(os.scriptdir(), "libs/noop")) -add_deps("cmake") -set_license("MIT") -on_install("linux", "macosx", "mingw", "windows", function (package) - import("package.tools.cmake").install(package, { }) -end) -package_end() - -package("tree-sitter-lua") -add_urls("https://github.com/tree-sitter-grammars/tree-sitter-lua.git") -add_versions("0.4.99", "e40f5b6e6df9c2d1d6d664ff5d346a75d71ee6b2") -add_versions("0.4.100", "e40f5b6e6df9c2d1d6d664ff5d346a75d71ee6b2") -add_deps("cmake", "noop") -set_license("MIT") --- This is the most fucky hack I've probably made. It's essentially: I don't --- want you to fucking regenerate the grammar file, cause it's already there. But --- since you want to regenerate it, how about I pass in a very legit version of tree-sitter CLI --- called "noop" so at least you have something to run! --- --- NOTE: This only works because the grammar file has already been generated. -on_install("mingw", "windows", "linux", "macosx", function (package) - local noop = package:dep("noop") - local config = { } - table.insert(config, "-DCMAKE_BUILD_TYPE=" .. (is_mode("debug") and "Debug" or "Release")) - table.insert(config, "-DBUILD_SHARED_LIBS=OFF") - table.insert(config, "-DTREE_SITTER_CLI=" .. path.join(noop:installdir(), "bin/noop")) - import("package.tools.cmake").install(package, config) -end) -package_end() - package("tgui") -- set_sourcedir(path.join(os.scriptdir(), "libs/tgui/")) add_urls("https://github.com/texus/TGUI.git") @@ -70,14 +39,15 @@ on_install("linux", "macosx", "mingw", "windows", function (package) end) package_end() -add_requires("raylib", "tgui", "nlohmann_json", "luajit", "noop", "tree-sitter", - "tree-sitter-lua") +add_requires("raylib", "tgui", "nlohmann_json", "luajit", "pugixml") add_rules("mode.debug", "mode.release") set_defaultmode("debug") target("rpgpp") +set_plat(os.host()) +set_arch(os.arch()) set_kind("static") -add_packages("raylib", "nlohmann_json", "luajit") +add_packages("raylib", "nlohmann_json", "luajit", "pugixml") set_languages("cxx17") add_includedirs("include/", "include/lua/") add_files("src/*.cpp", "src/lua/*.cpp") @@ -154,13 +124,12 @@ set_languages("cxx17") add_includedirs("include/", "include/editor/", os.dirs(path.join(os.scriptdir()))) add_files("src/editor/**.cpp") add_deps("rpgpp") -add_packages("raylib", "tgui", "nlohmann_json", "luajit", "noop", "tree-sitter", - "tree-sitter-lua") +add_packages("raylib", "tgui", "nlohmann_json", "luajit", "pugixml") after_build( function (target) - os.cp("$(curdir)/resources", "$(builddir)/$(plat)/$(arch)/$(mode)/", { async = true }) + os.cp("$(curdir)/resources", "./build/$(plat)/$(arch)/$(mode)/", { async = true }) if is_plat("linux", "macosx") then - os.cp("$(builddir)/$(plat)/$(arch)/$(mode)/librpgpp.a", "$(curdir)/game-src/lib/librpgpp.a", { async = true }) - os.cp("$(builddir)/$(plat)/$(arch)/$(mode)/librpgpplua.so", "$(curdir)/game-src/lib/librpgpplua.so", + os.cp("./build/$(plat)/$(arch)/$(mode)/librpgpp.a", "$(curdir)/game-src/lib/librpgpp.a", { async = true }) + os.cp("./build/$(plat)/$(arch)/$(mode)/librpgpplua.so", "$(curdir)/game-src/lib/librpgpplua.so", { async = true }) os.cp(path.join(target:pkg("luajit"):installdir(), "bin/luajit*"), "$(curdir)/execs/luajit", { async = true }) end @@ -170,13 +139,13 @@ after_build( function (target) os.cp(path.join(target:pkg("luajit"):installdir(), "bin/luajit.exe"), "$(curdir)/execs/luajit.exe", { async = true }) end - os.cp("$(curdir)/game-src", "$(builddir)/$(plat)/$(arch)/$(mode)/", { async = true }) - os.cp("$(curdir)/execs", "$(builddir)/$(plat)/$(arch)/$(mode)/", { async = true }) + os.cp("$(curdir)/game-src", "./build/$(plat)/$(arch)/$(mode)/", { async = true }) + os.cp("$(curdir)/execs", "./build/$(plat)/$(arch)/$(mode)/", { async = true }) os.rm("$(curdir)/game-src", { async = true }) os.rm("$(curdir)/execs", { async = true }) -- remove this line to test if the configuration file changes - os.cp("$(curdir)/rpgpp.ini", "$(builddir)/$(plat)/$(arch)/$(mode)/", { copy_if_different = true }) + os.cp("$(curdir)/rpgpp.ini", "./build/$(plat)/$(arch)/$(mode)/", { copy_if_different = true }) print("Pro tip: Check whether translations are up to date with `xmake check_translation`!") print("Environment:") print(" builddir: " .. "$(builddir)")