From cf74541678ff5aa65a918a80d2c199ee8c472b43 Mon Sep 17 00:00:00 2001 From: Bobby Lucero Date: Sun, 6 Oct 2024 02:04:40 -0400 Subject: [PATCH] Line number detail if > 999, click to set cursor pos, page scrolling (using shift for now, will change) --- Concept Art/PycronEditorGUI.aseprite | Bin 7391 -> 7844 bytes python/particles.py | 8 +- resources/LineNumberDetailCenter.png | Bin 0 -> 91 bytes resources/LineNumberDetailLeft.png | Bin 0 -> 117 bytes resources/LineNumberDetailRight.png | Bin 0 -> 114 bytes src/Pycron.cpp | 6 + src/State.h | 1 + src/StateManager.cpp | 5 +- src/StateManager.h | 1 + src/States/Editor/EditorState.cpp | 157 +++++++++++++++++++++++---- src/States/Editor/EditorState.h | 5 + src/States/GameState.cpp | 4 + src/States/GameState.h | 1 + src/Utilities.cpp | 5 + src/Utilities.h | 5 +- 15 files changed, 167 insertions(+), 31 deletions(-) create mode 100644 resources/LineNumberDetailCenter.png create mode 100644 resources/LineNumberDetailLeft.png create mode 100644 resources/LineNumberDetailRight.png diff --git a/Concept Art/PycronEditorGUI.aseprite b/Concept Art/PycronEditorGUI.aseprite index 4d05e93a887d66bd823bcba595ca14963e99e7a9..2f64ab4469ad673611cd13800d07ee988ce723a9 100644 GIT binary patch delta 1014 zcmca_xx|)fiQGh{IwlpljZKc+_5F+t46F*w3=9nX4F8#c6c~szY+$IE^LE-n-a`gF zt~Z;x%`FZxoH-=n6R?rdxFFezjpNlpp(}a8+Y5iH-VfsQo4x$SP2XF05?9`(bL8SpR!RSYOa-nf-3+Z}R1@p9;*H`S^0@v(5YWUyrUlyVa%q&}Zzbv)|R{ zzyEja-R;+y-?_R9EE}inag86~s;@g{zcz^NLp9RMY zH!wB?k>aI+ArBNUcMZLm9Yq=*mc$)#5)jc|oBKxh=&9ltzC|5ZUKVvd5d0#fy_iQw z@uutJb3Wf{<#{5771#Y2KAU#n=%eG`iZA=_6*JM?x^qwEjGCE^-*m38es3loetojO z@r8Ml{+@NH_WEva!JNDD;(eYii^J-TFSO0F|NnAl_Wb&it#$vi@3%?S1IfNi>;G@f zKmYb`^2FEmx3+7aJ#c09H%q38h9dP2nRkB&hi6~4`~D)R`O^RYi}#;#u$5n*9(w!v z)O~%o?ss>5>G%DA1BIy1I^Xc^tM2=AyQ5Zr+X+gK2Ueb_)@=WF>sG#{f2DlBm0ihN zTl+M&XG{Of`TeR`v;TYSGgmZ2fL!(S4)s=Yuh;*zdHQ#Yb9L_9ovaKEl{f10cGc|O z{j1;De&yQ>um9KluRn8O-_KX)B~x{;ufF)Y{_pS0&;Nhj`Du=9RN8_)L4SXrH{Q}W zQ@_q1&4&7-*(Ekt{?9P`wf*hSr)y7d-@W?(55r?=4!?iiHjn>n`Pig}vHp?#6xME_ z4_Fm=7?>GEkm664Ap;bDw;Z_|6a-i=SbBYL_q)!RWvY!A-u`RWgua&Q#Zg0K$>$|VUFU#iU0h3EZ e{@H(F^}qB5UaXoqbMfuMo%y@=GUOh=^b7!7_6+#| delta 587 zcmZ2td*71jzRX0XI;MD;jZKc+_4$kp46F*w3=9nX4F8#c6c~szY+$IE^Y+@tUM53< z*2G^5io3h}m{vSJwS!AQHikDP#GSF5L+z${_Qo5{axb<&N!art^XrqZKYrBD+qbQK zQl-uobN`;-zio`>Z?sR0(ci84EMt4PKnz5TWNZH1rOtMHUZW-pHJ^jCXj{r>%`_eEDKKV@0}a|d$g z-~aOHj=J#Io%6r!Tzl&(U%$_l@_SIRx##n%3g1oc{B_6w*PXDpS?wSV@1bJno}2Hr z_r z+5tv~BKLDL%Po&RYkQ`7`aqFX)i0CdH|{w2|K7N>@!q$^yAu`OxR)Jv_-U`UvdrO6 zf6jM@CG{!06B$(8`v3Hw%}X)AAeFpXoI$X6mytc#P96qkh7c1ZOT`)3!ImZ@?D+TU hLA^wp1JjhQvzo-U3d5>u1^)EmFDXBIoKV&U@s n&?e5=4>~3!Xg>Va70Sf$lY`B<{&0FYP&I?6tDnm{r-UW|zb6^B literal 0 HcmV?d00001 diff --git a/resources/LineNumberDetailLeft.png b/resources/LineNumberDetailLeft.png new file mode 100644 index 0000000000000000000000000000000000000000..fe553f847494b987dc43304a94f87d09c825cb0b GIT binary patch literal 117 zcmeAS@N?(olHy`uVBq!ia0vp^%pf)g8<5OVx^f;!*?77*hH%VGPH1TQZ@&27VM(c~ zU;k&uUEA>gI?vuy2SDIR153t#2GMo>_u(WdfML1I=OZ MboFyt=akR{0E&_-wEzGB literal 0 HcmV?d00001 diff --git a/resources/LineNumberDetailRight.png b/resources/LineNumberDetailRight.png new file mode 100644 index 0000000000000000000000000000000000000000..cb22a79481e1eb9692f0abf17298f77b849bf877 GIT binary patch literal 114 zcmeAS@N?(olHy`uVBq!ia0vp^%pf)g8<5OVx^f;!S$euShH%VG{!wrI%AT1gbP0l+XkKVy7kc literal 0 HcmV?d00001 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); }