Initial cursor implementation

This commit is contained in:
Bobby Lucero 2024-10-01 20:52:51 -04:00
parent 6e19d50a5a
commit 8b1f403c87
8 changed files with 154 additions and 33 deletions

View File

@ -247,6 +247,41 @@ void Graphics::Pixel(int x, int y, int paletteIndex) {
m_virtualScreenColorBuffer[y * m_screenWidth + x] = paletteIndex;
}
void Graphics::Line(int x0, int y0, int x1, int y1, int paletteIndex) {
int dx = x1 - x0; // Change in x
int dy = y1 - y0; // Change in y
int abs_dx = std::abs(dx);
int abs_dy = std::abs(dy);
int sx = (dx > 0) ? 1 : -1; // Step direction in x
int sy = (dy > 0) ? 1 : -1; // Step direction in y
// Choose the primary axis for iteration
if (abs_dx > abs_dy) {
int err = abs_dx / 2; // Error value
for (int i = 0; i <= abs_dx; i++) {
Pixel(x0, y0, paletteIndex); // Plot the pixel
err -= abs_dy; // Update error term
if (err < 0) {
y0 += sy; // Move in y direction
err += abs_dx; // Update error term
}
x0 += sx; // Always move in x direction
}
} else {
int err = abs_dy / 2; // Error value
for (int i = 0; i <= abs_dy; i++) {
Pixel(x0, y0, paletteIndex); // Plot the pixel
err -= abs_dx; // Update error term
if (err < 0) {
x0 += sx; // Move in x direction
err += abs_dy; // Update error term
}
y0 += sy; // Always move in y direction
}
}
}
void Graphics::Circle(int x, int y, int radius, int paletteIndex) {
Ellipse(x, y, radius, radius, paletteIndex);
}

View File

@ -70,6 +70,7 @@ public:
void Clear(int paletteIndex);
void Pixel(int x, int y, int paletteIndex);
void Line(int x0, int y0, int x1, int y1, int paletteIndex);
void Circle(int x, int y, int radius, int paletteIndex);
void Ellipse(int x, int y, int width, int height, int paletteIndex);
void EllipseBorder(int x, int y, int width, int height, int paletteIndex);

View File

@ -45,6 +45,19 @@ void Pycron::StartGameLoop() {
}
m_graphics->updateVMVars(m_vm);
m_graphics->draw(this->m_stateManager);
char c = (char)GetCharPressed();
while(c > 0){
m_stateManager->OnCharPressed(c);
c = (char)GetCharPressed();
}
for (int key = KeyboardKey::KEY_BACK; key < KeyboardKey::KEY_KP_EQUAL; ++key) {
if(IsKeyPressed(key) || IsKeyPressedRepeat(key)){
m_stateManager->OnKeyPressed(key);
}
}
}
}

View File

@ -67,3 +67,11 @@ void StateManager::Draw() {
}
}
void StateManager::OnKeyPressed(int key) {
m_currentState->OnKeyPressed(key);
}
void StateManager::OnCharPressed(char c) {
m_currentState->OnCharPressed(c);
}

View File

@ -31,6 +31,9 @@ public:
void ChangeState(StateManager::StateType state);
void OnKeyPressed(int key);
void OnCharPressed(char c);
void RequestLoadGame();
void RequestRunGame();
void RequestStopGame();

View File

@ -8,6 +8,7 @@
#include "EditorState.h"
#include "../../Graphics/PycronImage.h"
#include "../../Pycron.h"
#include <raylib.h>
EditorState::EditorState(pkpy::VM *vm, Graphics *graphics) : m_vm(vm), m_graphics(graphics){
@ -15,14 +16,15 @@ EditorState::EditorState(pkpy::VM *vm, Graphics *graphics) : m_vm(vm), m_graphic
Token a(TokenType::Keyword, "Test");
std::string randomSource = Pycron::loadFileToString("../python/syntaxTest.py");
std::string randomSource = Pycron::loadFileToString("../python/main.py");
m_baseBackgroundColor = 56;
m_baseTextColor = 63;
m_shadowColor = 28;
m_baseTextColor = 42;
m_lineNumberBackgroundColor = 57;
m_lineNumberTextColor = 6;
m_unknownTextColor = 4;
m_identifierTextColor = 43;
m_identifierTextColor = 63;
m_keywordTextColor = 31;
m_builtinTextColor = 23;
m_numericalLiteralTextColor = 32;
@ -31,23 +33,30 @@ EditorState::EditorState(pkpy::VM *vm, Graphics *graphics) : m_vm(vm), m_graphic
m_operatorTextColor = 45;
m_commentTextColor = 60;
m_topLetterSpacing = 0;
m_bottomLetterSpacing = 1;
m_leftLetterSpacing = 0;
m_rightLetterSpacing = 1;
m_cursorX = 0;
m_cursorY = 0;
m_cursorBlinkTimer = 0;
m_cursorBlinkInterval = 0.5;
m_charWidth = m_leftLetterSpacing + m_graphics->GetCurrentFontWidth() + m_rightLetterSpacing; // Final size of char with spacing. If the literal width of the font is n, the final width is n + spacing.
m_charHeight = m_topLetterSpacing + m_graphics->GetCurrentFontHeight() + m_bottomLetterSpacing;
m_textWidth = (int)(m_graphics->m_screenWidth / m_charWidth);
m_textHeight = (int)(m_graphics->m_screenHeight / m_charHeight);
m_width = (int)(m_graphics->m_screenWidth / m_charWidth);
m_height = (int)(m_graphics->m_screenHeight / m_charHeight);
m_characterBuffer = std::vector<char>(m_textWidth * m_textHeight);
m_foregroundIndexBuffer = std::vector<uint8_t>(m_textWidth * m_textHeight);
m_backgroundIndexBuffer = std::vector<uint8_t>(m_textWidth * m_textHeight);
m_characterBuffer = std::vector<char>(m_width * m_height);
m_foregroundIndexBuffer = std::vector<uint8_t>(m_width * m_height);
m_backgroundIndexBuffer = std::vector<uint8_t>(m_width * m_height);
m_dirtyFlags = std::vector<bool>(m_textHeight);
m_dirtyFlags = std::vector<bool>(m_height);
m_drawShadows = true;
Clear();
@ -62,28 +71,20 @@ EditorState::~EditorState() {
}
void EditorState::Draw() {
m_graphics->Clear(0);
int bg = 28;
for (int i = 0; i < m_characterBuffer.size(); ++i) {
int x = (i % m_textWidth) * m_charWidth;
int y = (i / m_textWidth) * m_charHeight;
m_graphics->Rect(x, y, m_charWidth, m_charHeight, m_backgroundIndexBuffer[i]);
m_graphics->Char(m_characterBuffer[i], x + m_leftLetterSpacing + 1, y + m_topLetterSpacing + 1, bg);
m_graphics->Char(m_characterBuffer[i], x + m_leftLetterSpacing, y + m_topLetterSpacing, m_foregroundIndexBuffer[i]);
}
// Set text and color buffers if needed
if(m_dirty){
Clear();
m_dirty = false;
for (int i = 0; i < m_text.size(); ++i) {
// Line numbers TODO: maybe not have this as part of the buffer, instead as a custom bar. (Allows for more custom functionality such as bookmarks)
// std::string lineNumber = std::to_string(std::abs(m_cursorY - i));
// if(i == m_cursorY) lineNumber = std::to_string(m_cursorY);
std::string lineNumber = std::to_string(i);
int size = 2;
int diff = size - (int)lineNumber.size();
if(diff > 0) lineNumber = std::string(diff, ' ') + lineNumber;
Text(lineNumber, 0, i, m_lineNumberTextColor, m_lineNumberBackgroundColor);
Text(lineNumber, 0, i, i == m_cursorY ? m_lineNumberTextColor : m_commentTextColor, m_lineNumberBackgroundColor);
// Text handling
auto tokens = m_pythonTokenizer->tokenizeLine(m_text[i]);
@ -117,6 +118,37 @@ void EditorState::Draw() {
}
}
m_graphics->Clear(0);
// draw text with info from color buffers
for (int i = 0; i < m_characterBuffer.size(); ++i) {
int x = (i % m_width) * m_charWidth;
int y = (i / m_width) * m_charHeight;
m_graphics->Rect(x, y, m_charWidth, m_charHeight, m_backgroundIndexBuffer[i]);
if(m_drawShadows) m_graphics->Char(m_characterBuffer[i], x + m_leftLetterSpacing + 1, y + m_topLetterSpacing + 1, m_shadowColor);
m_graphics->Char(m_characterBuffer[i], x + m_leftLetterSpacing, y + m_topLetterSpacing, m_foregroundIndexBuffer[i]);
}
if(m_cursorVisible) {
int x = (m_cursorX + 2) * m_charWidth;
int y = m_cursorY * m_charHeight;
int index = m_cursorY * m_width + (m_cursorX + 2);
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]);
// m_graphics->Line(x - 1, y, x - 1, y + m_charHeight - 1, 63);
std::string s(1, m_characterBuffer[index]);
m_graphics->Text(s, x, y, m_backgroundIndexBuffer[index]);
}
// Cursor blink
m_cursorBlinkTimer += GetFrameTime();
if(m_cursorBlinkTimer > m_cursorBlinkInterval){
m_cursorVisible = !m_cursorVisible;
m_cursorBlinkTimer = 0.0;
}
}
void EditorState::OnEnter() {
@ -128,11 +160,33 @@ void EditorState::OnExit() {
}
void EditorState::OnKeyPressed(int key) {
std::cout << key << ". \n";
if(key == KEY_LEFT && m_cursorX > 0){
m_cursorX--;
}
if(key == KEY_RIGHT && m_cursorX < m_width - 1 - 2){
m_cursorX++;
}
if(key == KEY_UP && m_cursorY > 0){
m_cursorY--;
}
if(key == KEY_DOWN && m_cursorY < m_height - 1){
m_cursorY++;
}
m_cursorVisible = true;
m_cursorBlinkTimer = 0;
m_dirty = true;
if(key == KEY_GRAVE) m_drawShadows = !m_drawShadows;
}
void EditorState::OnCharPressed(char character){
}
void EditorState::Clear() {
for (int i = 0; i < m_textWidth * m_textHeight; ++i) {
for (int i = 0; i < m_width * m_height; ++i) {
m_characterBuffer[i] = ' ';
m_foregroundIndexBuffer[i] = m_baseTextColor;
m_backgroundIndexBuffer[i] = m_baseBackgroundColor;
@ -143,11 +197,11 @@ 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;
int charY = y;
if(charX < 0 || charY < 0 || charX >= m_textWidth || charY >= m_textHeight){
if(charX < 0 || charY < 0 || charX >= m_width || charY >= m_height){
return;
}
char c = text[i];
int index = y * m_textWidth + (x + i);
int index = y * m_width + (x + i);
m_characterBuffer[index] = c;
m_backgroundIndexBuffer[index] = bg;
m_foregroundIndexBuffer[index] = fg;
@ -156,9 +210,6 @@ void EditorState::Text(const std::string &text, int x, int y, int fg, int bg) {
}
}
void EditorState::OnCharPressed(char character) {
}
void EditorState::LoadStringToBuffer(const std::string &text) {
m_text.clear();

View File

@ -24,8 +24,12 @@ private:
Graphics* m_graphics;
PythonTokenizer* m_pythonTokenizer;
// Size of the character in pixels
uint8_t m_charWidth, m_charHeight;
uint8_t m_textWidth, m_textHeight;
// Size of the editor in characters
uint8_t m_width, m_height;
uint8_t m_topLetterSpacing, m_bottomLetterSpacing, m_leftLetterSpacing, m_rightLetterSpacing;
// Text Buffer
std::vector<char> m_characterBuffer;
@ -38,6 +42,7 @@ private:
// Theming
uint8_t m_baseBackgroundColor;
uint8_t m_shadowColor;
uint8_t m_baseTextColor;
uint8_t m_lineNumberBackgroundColor;
uint8_t m_lineNumberTextColor;
@ -51,9 +56,16 @@ private:
uint8_t m_operatorTextColor;
uint8_t m_commentTextColor;
int m_cursorX;
int m_cursorY;
bool m_cursorVisible;
float_t m_cursorBlinkTimer;
float_t m_cursorBlinkInterval;
bool m_dirty;
bool m_drawShadows;
void Clear();
void Text(const std::string &text, int x, int y, int fg = 0, int bg = 63);

View File

@ -117,7 +117,7 @@ bool PythonTokenizer::isPunctuation(char c) {
}
bool PythonTokenizer::isOperator(char c) {
return c == '+' || c == '-' || c == '*' || c == '/' || c == '=' || c == '<' || c == '>' || c == '!';
return c == '+' || c == '-' || c == '*' || c == '/' || c == '=' || c == '<' || c == '>' || c == '!' || c == ':';
}
std::string PythonTokenizer::readNumericLiteral(const std::string &line) {
@ -165,8 +165,6 @@ std::string PythonTokenizer::readStringLiteral(const std::string &line) {
m_currentPos++;
while (m_currentPos < line.length() && line[m_currentPos] != '"') {
m_currentPos++;
std::cout << m_currentPos;
}
if(line[m_currentPos] == '"') m_currentPos++;