diff --git a/Concept Art/PycronEditorGUI.aseprite b/Concept Art/PycronEditorGUI.aseprite index 4d05e93..2f64ab4 100644 Binary files a/Concept Art/PycronEditorGUI.aseprite and b/Concept Art/PycronEditorGUI.aseprite differ diff --git a/python/particles.py b/python/particles.py index 70b9e70..8449ca6 100644 --- a/python/particles.py +++ b/python/particles.py @@ -102,7 +102,7 @@ class Particles(Scene): if(p.size < 0): self.waterParts.remove(p) - + if(mouse(0)): rad = sin(self.counter * 0.01) * 50 @@ -150,8 +150,4 @@ class Particles(Scene): # triangle(mouseX, mouseY, x2, y2, x3, y3, 9) - # lineTri(mouseX, mouseY, x2, y2, x3, y3, 8) - - - - + # lineTri(mouseX, mouseY, x2, y2, x3, y3, 8) \ No newline at end of file diff --git a/resources/LineNumberDetailCenter.png b/resources/LineNumberDetailCenter.png new file mode 100644 index 0000000..ff3d81e Binary files /dev/null and b/resources/LineNumberDetailCenter.png differ diff --git a/resources/LineNumberDetailLeft.png b/resources/LineNumberDetailLeft.png new file mode 100644 index 0000000..fe553f8 Binary files /dev/null and b/resources/LineNumberDetailLeft.png differ diff --git a/resources/LineNumberDetailRight.png b/resources/LineNumberDetailRight.png new file mode 100644 index 0000000..cb22a79 Binary files /dev/null and b/resources/LineNumberDetailRight.png differ diff --git a/src/Pycron.cpp b/src/Pycron.cpp index fcff316..9029ff3 100644 --- a/src/Pycron.cpp +++ b/src/Pycron.cpp @@ -58,6 +58,12 @@ void Pycron::StartGameLoop() { m_stateManager->OnKeyPressed(key); } } + + for (int button = MouseButton::MOUSE_BUTTON_LEFT; button < MouseButton::MOUSE_BUTTON_BACK; ++button) { + if(IsMouseButtonPressed(button)){ + m_stateManager->OnMousePressed(button); + } + } } } diff --git a/src/State.h b/src/State.h index 35cdb2f..fde32e7 100644 --- a/src/State.h +++ b/src/State.h @@ -13,5 +13,6 @@ public: virtual void OnExit() = 0; virtual void OnKeyPressed(int key) = 0; virtual void OnCharPressed(char character) = 0; + virtual void OnMousePressed(int button) = 0; }; diff --git a/src/StateManager.cpp b/src/StateManager.cpp index 576a122..4e5449f 100644 --- a/src/StateManager.cpp +++ b/src/StateManager.cpp @@ -15,7 +15,6 @@ StateManager::~StateManager() { m_currentState = nullptr; delete m_gameState; delete m_editorState; - delete m_graphics; } @@ -75,3 +74,7 @@ void StateManager::OnCharPressed(char c) { m_currentState->OnCharPressed(c); } +void StateManager::OnMousePressed(int button) { + m_currentState->OnMousePressed(button); +} + diff --git a/src/StateManager.h b/src/StateManager.h index 3da2f38..c22adbe 100644 --- a/src/StateManager.h +++ b/src/StateManager.h @@ -33,6 +33,7 @@ public: void OnKeyPressed(int key); void OnCharPressed(char c); + void OnMousePressed(int button); void RequestLoadGame(); void RequestRunGame(); diff --git a/src/States/Editor/EditorState.cpp b/src/States/Editor/EditorState.cpp index fc68c02..c9d4b60 100644 --- a/src/States/Editor/EditorState.cpp +++ b/src/States/Editor/EditorState.cpp @@ -7,15 +7,19 @@ #include #include #include "EditorState.h" +#include "../../Utilities.h" EditorState::EditorState(pkpy::VM *vm, Graphics *graphics) : m_vm(vm), m_graphics(graphics){ m_pythonTokenizer = new PythonTokenizer(); - std::string randomSource = Pycron::loadFileToString("../python/main.py"); + std::string randomSource = Pycron::loadFileToString("../python/particles.py"); m_editorFrame = m_graphics->loadImage("../resources/EditorFrame.png"); + m_LineNumberDetailLeft = m_graphics->loadImage("../resources/LineNumberDetailLeft.png"); + m_LineNumberDetailCenter = m_graphics->loadImage("../resources/LineNumberDetailCenter.png"); + m_LineNumberDetailRight = m_graphics->loadImage("../resources/LineNumberDetailRight.png"); m_baseBackgroundColor = 56; m_shadowColor = 28; @@ -89,6 +93,9 @@ void EditorState::Draw() { if(m_dirty){ Clear(); m_dirty = false; + + int cursorPos = m_scrollY + m_cursorY; + for (int i = 0; i < m_height; ++i) { int index = i + m_scrollY; @@ -99,6 +106,23 @@ void EditorState::Draw() { auto tokens = m_pythonTokenizer->tokenizeLine(m_text[index]); int currentPos = 0; + if(index == cursorPos){ + std::string lineNumber = std::to_string(cursorPos); + int offset = std::max((int)lineNumber.size() - 3, 0); + bool collision = false; + for (int j = 0; j < offset; ++j) { + if(m_text[index].size() < offset) break; + if(m_text[index][j] != ' '){ + collision = true; + break; + } + } + if(!collision) offset = 0; + currentPos = offset; + } + + + for (int j = 0; j < tokens.size(); ++j) { int color = m_baseTextColor; TokenType type = tokens[j].type; @@ -141,9 +165,25 @@ void EditorState::Draw() { // Draw the cursor if(m_cursorVisible) { - int x = m_cursorX * m_charWidth + m_textBounds->x; + int currentLine = m_scrollY + m_cursorY; + std::string lineNumber = std::to_string(currentLine); + int offset = std::max((int)lineNumber.size() - 3, 0); + + bool collision = false; + for (int i = 0; i < offset; ++i) { + if(m_text[currentLine].size() < offset) break; + if(m_text[currentLine][i] != ' '){ + collision = true; + break; + } + } + + if(!collision) offset = 0; + + int x = (m_cursorX + offset) * m_charWidth + m_textBounds->x; int y = m_cursorY * m_charHeight + m_textBounds->y; - int index = m_cursorY * m_width + m_cursorX; + + int index = m_cursorY * m_width + (m_cursorX + offset); if(m_drawShadows) m_graphics->Rect(x, y, m_charWidth + 1, m_charHeight + 1, m_shadowColor); m_graphics->Rect(x - 1, y - 1, m_charWidth + 1, m_charHeight + 1, m_foregroundIndexBuffer[index]); @@ -157,18 +197,50 @@ void EditorState::Draw() { m_cursorVisible = !m_cursorVisible; m_cursorBlinkTimer = 0.0; } + // Editor frame image + m_graphics->Img(m_editorFrame, 0, 0); // Line Numbers for (int i = 0; i < m_height; ++i) { - std::string lineNumber = std::to_string(i + m_scrollY); - int delta = 3 - (int)lineNumber.size(); + int lineNum = i + m_scrollY + 1; + std::string lineNumber = std::to_string(lineNum); + int delta = std::max(0, 3 - (int)lineNumber.size()); lineNumber = std::string(delta, ' ') + lineNumber; + lineNumber = lineNumber.substr(lineNumber.size() - 3); + int highlight = i == m_cursorY ? m_lineNumberTextColor : m_commentTextColor; + + if(lineNum > 999){ + lineNumber[0] = ' '; + int dotX = m_lineNumberWindowXOffset; + int dotY = m_lineNumberWindowYOffset + (i * m_charHeight) + m_graphics->GetCurrentFontHeight() - 1; + m_graphics->Pixel(dotX, dotY, highlight); + m_graphics->Pixel(dotX + 2, dotY, highlight); + m_graphics->Pixel(dotX + 4, dotY, highlight); + } + m_graphics->Text(lineNumber, m_lineNumberWindowXOffset, m_lineNumberWindowYOffset + (i * m_charHeight), highlight); } - // Editor frame image - m_graphics->Img(m_editorFrame, 0, 0); + // Line Number Detail + if(m_scrollY + 1 + m_cursorY > 999){ + int lineNum = m_scrollY + 1 + m_cursorY; + std::string lineNumber = std::to_string(lineNum); + + int lineNumberDetailXOffset = 3; + int lineNumberDetailYOffset = 3; + + int yOffset = m_lineNumberWindowYOffset - lineNumberDetailYOffset + (m_cursorY * (m_graphics->GetCurrentFontHeight() + 1)); + + m_graphics->Img(m_LineNumberDetailLeft, m_lineNumberWindowXOffset - lineNumberDetailXOffset, yOffset); + for (int i = 0; i < lineNumber.size(); ++i) { + int offset = m_lineNumberWindowXOffset + (i * 6); + m_graphics->Img(m_LineNumberDetailCenter, offset, yOffset); + } + m_graphics->Img(m_LineNumberDetailRight, m_lineNumberWindowXOffset + (lineNumber.size() * 6), yOffset); + m_graphics->Text(lineNumber, m_lineNumberWindowXOffset, yOffset + lineNumberDetailYOffset, m_lineNumberTextColor); + } + //m_graphics->RectBorder(m_textBounds->x, m_textBounds->y, m_textBounds->width, m_textBounds->height, 23); @@ -190,30 +262,48 @@ void EditorState::OnKeyPressed(int key) { m_cursorX++; } if(key == KEY_UP){ - if( m_cursorY > 0) - { - m_cursorY--; - } - else - { - if(m_scrollY > 0) + if(IsKeyDown(KEY_LEFT_SHIFT)){ + m_scrollY -= m_height; + bool success = m_scrollY > 0; + if(!success && m_cursorY > 0) m_cursorY--; + }else{ + if( m_cursorY > 0) + { + m_cursorY--; + } + else { m_scrollY--; } } + + if(m_scrollY < 0){ + m_scrollY = 0; + } + } if(key == KEY_DOWN ) { - if(m_cursorY < std::min(m_height - 1, static_cast(m_text.size()) - 1)) - { - m_cursorY++; - } - else - { - if(m_scrollY + m_height < m_text.size()) + if(IsKeyDown(KEY_LEFT_SHIFT)){ + m_scrollY += m_height; + bool success = m_scrollY + m_height <= m_text.size() - 1; + if(!success && m_cursorY < std::min(m_height - 1, static_cast(m_text.size()) - 1)) m_cursorY++; + }else{ + if(m_cursorY < std::min(m_height - 1, static_cast(m_text.size()) - 1)) + { + m_cursorY++; + } + else + { m_scrollY++; + } } + + if(m_scrollY + m_height > m_text.size() - 1){ + m_scrollY = m_text.size() - 1 - m_height; + } + } @@ -229,6 +319,27 @@ void EditorState::OnCharPressed(char character){ } +void EditorState::OnMousePressed(int button) { + int x = m_graphics->mouseX(); + int y = m_graphics->mouseY(); + + if(Utilities::RectContainsPoint(m_textBounds, x, y)){ + x -= m_textWindowXOffset; + y -= m_textWindowYOffset; + + x /= m_charWidth; + y /= m_charHeight; + + m_cursorX = x; + m_cursorY = y; + + m_cursorVisible = true; + m_cursorBlinkTimer = 0; + m_dirty = true; + } + +} + void EditorState::Clear() { for (int i = 0; i < m_width * m_height; ++i) { m_characterBuffer[i] = ' '; @@ -237,6 +348,7 @@ void EditorState::Clear() { } } + void EditorState::Text(const std::string &text, int x, int y, int fg, int bg) { for (int i = 0; i < text.size(); ++i) { int charX = x + i; @@ -254,7 +366,6 @@ void EditorState::Text(const std::string &text, int x, int y, int fg, int bg) { } } - void EditorState::LoadStringToBuffer(const std::string &text) { m_text.clear(); @@ -273,7 +384,7 @@ void EditorState::LoadStringToBuffer(const std::string &text) { for (const auto& line : lines) { m_text.push_back(line); } - + m_dirty = true; } diff --git a/src/States/Editor/EditorState.h b/src/States/Editor/EditorState.h index 09137ac..0b8b45e 100644 --- a/src/States/Editor/EditorState.h +++ b/src/States/Editor/EditorState.h @@ -20,6 +20,7 @@ public: void OnExit() override; void OnKeyPressed(int key) override; void OnCharPressed(char character) override; + void OnMousePressed(int button) override; private: pkpy::VM* m_vm; @@ -29,6 +30,10 @@ private: // Editor images PycronImage* m_editorFrame; + PycronImage* m_LineNumberDetailLeft; + PycronImage* m_LineNumberDetailCenter; + PycronImage* m_LineNumberDetailRight; + // Size of the character in pixels uint8_t m_charWidth, m_charHeight; diff --git a/src/States/GameState.cpp b/src/States/GameState.cpp index 1e12fbb..c3d9582 100644 --- a/src/States/GameState.cpp +++ b/src/States/GameState.cpp @@ -102,3 +102,7 @@ void GameState::OnCharPressed(char character) { } +void GameState::OnMousePressed(int button) { + +} + diff --git a/src/States/GameState.h b/src/States/GameState.h index 8a100cc..99e65f5 100644 --- a/src/States/GameState.h +++ b/src/States/GameState.h @@ -16,6 +16,7 @@ public: void OnExit() override; void OnKeyPressed(int key) override; void OnCharPressed(char character) override; + void OnMousePressed(int button) override; private: diff --git a/src/Utilities.cpp b/src/Utilities.cpp index 5a42308..93840fb 100644 --- a/src/Utilities.cpp +++ b/src/Utilities.cpp @@ -3,6 +3,7 @@ // #include "Utilities.h" + namespace Utilities { Color ColorFromHex(int hexValue) { // Extract red, green, blue, and alpha components from the hexadecimal value @@ -18,4 +19,8 @@ namespace Utilities { // Create and return the color return ColorFromNormalized({ rf, gf, bf, 1.0f }); // Alpha is set to 1.0 (fully opaque) } + + bool RectContainsPoint(pycron::Rectangle* r, int x, int y){ + return x >= r->x && x <= r->x + r->width && y >= r->y && y <= r->y + r->height; + } } diff --git a/src/Utilities.h b/src/Utilities.h index a7adf5d..0f62ae7 100644 --- a/src/Utilities.h +++ b/src/Utilities.h @@ -1,7 +1,10 @@ #pragma once #include "raylib.h" +#include "Utilities.h" +#include "Graphics/Rectangle.h" + namespace Utilities { Color ColorFromHex(int hexValue); - + bool RectContainsPoint(pycron::Rectangle* r, int x, int y); }