Easy Notepad - Aplikacja Notatnik

Easy Notepad - Aplikacja Notatnik
tBane
  • Rejestracja: dni
  • Ostatnio: dni
  • Lokalizacja: Poznań
  • Postów: 539
0

Cześć. Pracuję obecnie nad aplikacją typy notatnik i mam problem. Nie mogę zlokalizować błędu, który objawia sie tym, że źle oblicza cursorPosition.y.
Dla kolejnych linii daje wartości (cur) 0, 0 , 1, 2 ... zamiast 0, 1, 2, ... . Czyli zaczyna liczyć od dwóch zer a tak nie powinno być. Jakby ktoś mógł zerknąć na kod i wyjaśnić mi dlaczego tak jest. Pierwszy raz pisze taką aplikację więc proszę o wyrozumiałość :-)

pełny kod (tak żeby odpalić apkę)
https://github.com/tBane1995/Easy-Notepad

screenshot-20250617075306.png

Kod main/

Kopiuj
#include <SFML/Graphics.hpp>
#include <iostream>
#include <vector>
#include <functional>
#include <cmath>
#include <string>

#include "window.hpp"
#include "SFML_intro.hpp"
#include "mouse.hpp"
#include "elementGUI.hpp"
#include "scrollbar.hpp"


sf::Color text_color = sf::Color(188, 190, 196);
sf::Color background_color = sf::Color(30, 31, 34, 255);
sf::Color selection_color = sf::Color(33, 66, 131, 255);

sf::Font font;
short characterSize;

Scrollbar* scrollbar;

std::wstring text;
std::vector < sf::Text* > lines;

sf::RectangleShape cursor;
sf::Vector2i cursorPosition = sf::Vector2i(0, 0);

sf::Clock timeClock;
sf::Time currentTime;



std::vector < sf::Text* > wrap_text(int line_width, std::wstring text) {
    
    std::vector < sf::Text* > wrapped_text;

    std::wstring line = L"";
    std::wstring word = L"";

    for (auto& character : text) {
        if (sf::Text(word + character, font, characterSize).getGlobalBounds().width > line_width) {

            if (line != L"") {
                sf::Text* t = new sf::Text(line, font, characterSize);
                wrapped_text.push_back(t);
                line = L"";
            }

            // word longer than line
            std::wstring l = L"";
            word = word + character;
            for (wchar_t& c : word) {
                if (sf::Text(l+c, font, characterSize).getGlobalBounds().width > line_width) {
                    sf::Text* t = new sf::Text(l, font, characterSize);
                    wrapped_text.push_back(t);
                    l = c;
                }else 
                    l = l + c;
            }

            sf::Text* t = new sf::Text(l, font, characterSize);
            wrapped_text.push_back(t);

            word = L"";
        }
        else if (sf::Text(line + word + character, font, characterSize).getGlobalBounds().width > line_width)
        {
            sf::Text* t = new sf::Text(line, font, characterSize);
            wrapped_text.push_back(t);

            line = L"";
            word = word + character;
        }
        else if (character == L'\n') {

            if (sf::Text(line + word, font, characterSize).getGlobalBounds().width > line_width) {
                sf::Text* t = new sf::Text(line, font, characterSize);
                wrapped_text.push_back(t);

                sf::Text* t2 = new sf::Text(word + L"\n", font, characterSize);
                wrapped_text.push_back(t2);

                line = L"";
                word = L"";
            }
            else {
                sf::Text* t = new sf::Text(line + word + L"\n", font, characterSize);
                wrapped_text.push_back(t);

                line = L"";
                word = L"";
            }

        }
        else if (character == L' ' || character == L'\t') {
            if (sf::Text(line + word, font, characterSize).getGlobalBounds().width > line_width) {
                sf::Text* t = new sf::Text(line + L"\n", font, characterSize);
                wrapped_text.push_back(t);
                line = L"";
            }
            else {
                line = line + word + character;
            }

            word = L"";
        }
        else {
            word = word + character;
        }
    }

    if (line != L"" || word != L"") {
        sf::Text* t = new sf::Text(line + word, font, characterSize);
        wrapped_text.push_back(t);
    }

    return wrapped_text;

}

sf::Vector2i getCursorPosition() {

    if (lines.empty())
        return sf::Vector2i(0, 0);

    if (worldMousePosition.y >= lines.back()->getGlobalBounds().top) {

        for (size_t i = 0; i < lines.back()->getString().toWideString().size(); ++i) {
            sf::Vector2f charPos = lines.back()->findCharacterPos(i);
            sf::Vector2f nextPos = lines.back()->findCharacterPos(i + 1);

            float charWidth = nextPos.x - charPos.x;

            if (worldMousePosition.x < charPos.x + charWidth / 2.f) {
                //std::cout << "cursor on position: " << i << "," << lines.size() - 1 << "\n";
                return sf::Vector2i(i, lines.size() - 1);
            }
        }

        //std::cout << "cursor on position: " << lines.back()->getString().toWideString().size() << "," << lines.size() - 1 << "\n";
        return sf::Vector2i(lines.back()->getString().toWideString().size(), lines.size() - 1);
    }
        
    

    for (int t = 0; t < lines.size(); t++) {

        

        for (size_t i = 0; i < lines[t]->getString().toWideString().size() - 1; ++i) {

            sf::Vector2f charPos = lines[t]->findCharacterPos(i);
            float nextX = lines[t]->findCharacterPos(i + 1).x;

            sf::FloatRect charRect(charPos.x, charPos.y, nextX - charPos.x, font.getLineSpacing(characterSize));

            if (charRect.contains(worldMousePosition)) {

                if (worldMousePosition.x < charRect.left + charRect.width / 2) {
                    //std::cout << "cursor on position: " << i << "," << t << "\n";
                    return sf::Vector2i(i, t);
                }
                else {
                    //std::cout << "cursor on position: " << i+1 << "," << t << "\n";
                    return sf::Vector2i(i + 1, t);
                }
                    

            }

        }

        sf::Vector2f charPos; 
        if (lines[t]->getString().toWideString().back() == L'\n') {

            charPos = lines[t]->findCharacterPos(lines[t]->getString().toWideString().size() - 1);
            if (worldMousePosition.y >= charPos.y &&
                worldMousePosition.y <= charPos.y + font.getLineSpacing(characterSize) &&
                worldMousePosition.x >= charPos.x) {
                //std::cout << "cursor on position: " << lines[t]->getString().toWideString().size()-1 << "," << t << "\n";
                return sf::Vector2i(lines[t]->getString().toWideString().size()-1, t);
            }
        }
        else {
            charPos = lines[t]->findCharacterPos(lines[t]->getString().toWideString().size());
            if (worldMousePosition.y >= charPos.y &&
                worldMousePosition.y <= charPos.y + font.getLineSpacing(characterSize) &&
                worldMousePosition.x >= charPos.x) {
                //std::cout << "cursor on position: " << lines[t]->getString().toWideString().size() << "," << t << "\n";
                return sf::Vector2i(lines[t]->getString().toWideString().size(), t);
            }
        }
            

        

    }

    return sf::Vector2i(lines.back()->getString().toWideString().size(), lines.size() - 1);
}

int getCursorIndex(sf::Vector2i position) {
    int index = 0;
    for (int i = 0; i < position.y && i < lines.size(); ++i) {
        index += lines[i]->getString().toWideString().size();
    }
    index += position.x;
    //std::cout << "index: " << index << "\n";
    return index;
}

sf::Vector2i getCursorFromIndex(int index) {
    if (lines.empty())
        return sf::Vector2i(0, 0);

    int current = 0;
    for (int y = 0; y < lines.size(); ++y) {
        int lineSize = lines[y]->getString().getSize();

        if (index <= current + lineSize) {
            return sf::Vector2i(index - current, y);
        }

        current += lineSize;
    }

    // Jeśli index wykracza poza długość tekstu, ustaw na koniec ostatniej linii
    return sf::Vector2i(lines.back()->getString().toWideString().size(), lines.size() - 1);
}

void linesPositioning() {

    sf::Vector2f position(0, float(-scrollbar->scroll_value) * font.getLineSpacing(characterSize));

    for (int i = 0; i < lines.size();i+=1) {
        sf::Vector2f p = sf::Vector2f(0, float(i) * font.getLineSpacing(characterSize));
        p = p + sf::Vector2f(position);
        lines[i]->setPosition(p);
    }
}

class Selection {
public:

    int start_index = 0;
    int end_index = 0;

    Selection() {
        start_index = 0;
        end_index = 0;
    }

    ~Selection() {}

    void draw() {

        sf::Vector2i start_position;
        sf::Vector2i end_position;

        if (start_index < end_index) {
            start_position = getCursorFromIndex(start_index);
            end_position = getCursorFromIndex(end_index);
        }
        else {
            start_position = getCursorFromIndex(end_index);
            end_position = getCursorFromIndex(start_index);
        }

        int start_x = start_position.x;
        int end_x = end_position.x;

        int start_y = start_position.y;
        int end_y = end_position.y;

        float rect_start_x = (start_x == 0) ? 0 : lines[start_y]->findCharacterPos(start_x).x;
        float rect_end_x = lines[end_y]->findCharacterPos(end_x).x;

        float rect_start_y = (start_x == 0) ? 0 : lines[start_y]->findCharacterPos(start_x).y;
        float rect_end_y = lines[end_y]->findCharacterPos(end_x).y;


        std::vector < sf::RectangleShape > rects;


        if (end_y == start_y && start_x != end_x) {
            sf::RectangleShape rect = sf::RectangleShape(sf::Vector2f(rect_end_x - rect_start_x + 1, font.getLineSpacing(characterSize)));
            rect.setPosition(rect_start_x, rect_start_y);
            rect.setFillColor(selection_color);
            rects.push_back(rect);
        }
        else if (end_y - start_y >= 1) {

            sf::RectangleShape top_rect = sf::RectangleShape(sf::RectangleShape(sf::Vector2f(window->getSize().x - rect_start_x, font.getLineSpacing(characterSize))));
            top_rect.setPosition(rect_start_x, rect_start_y);
            top_rect.setFillColor(selection_color);
            rects.push_back(top_rect);

            sf::RectangleShape center_rect = sf::RectangleShape(sf::RectangleShape(sf::Vector2f(window->getSize().x, (end_y - start_y - 1) * font.getLineSpacing(characterSize))));
            center_rect.setPosition(0, rect_start_y + font.getLineSpacing(characterSize));
            center_rect.setFillColor(selection_color);
            rects.push_back(center_rect);

            sf::RectangleShape bottom_rect = sf::RectangleShape(sf::RectangleShape(sf::Vector2f(rect_end_x, font.getLineSpacing(characterSize))));
            bottom_rect.setPosition(0, rect_end_y);
            bottom_rect.setFillColor(selection_color);
            rects.push_back(bottom_rect);
        }


        for (auto& rect : rects)
            window->draw(rect);
    }
};

Selection* selection = nullptr;

void setCursorPosition(sf::Vector2i cursor_position) {
    cursorPosition = cursor_position;

    if (cursor_position == sf::Vector2i(0, 0)) {
        cursor.setPosition(sf::Vector2f(0, 0));
        return;
    }

    if (lines.empty()) {
        cursor.setPosition(sf::Vector2f(0, 0));
        return;
    }


    std::wstring line = lines[cursorPosition.y]->getString().toWideString();

    if (line.size() == 0) {
        cursor.setPosition(lines[cursorPosition.y]->getPosition());    // poprawka
        return;
    }

    if (cursor_position.x < line.size()) {
        sf::Vector2f charPos = lines[cursorPosition.y]->findCharacterPos(cursor_position.x);
        cursor.setPosition(charPos.x, charPos.y);
        return;
    }


    sf::Vector2f endPos = lines[cursorPosition.y]->findCharacterPos(line.size());
    cursor.setPosition(endPos.x, endPos.y);

}

void setCursorLeft() {
    //std::cout << "Left" << "\n";
    if (cursorPosition.x > 0) {
        cursorPosition.x -= 1;
    }
    else {
        if (!lines.empty() && cursorPosition.y > 0) {
            cursorPosition.y -= 1;
            int last_character_index = (lines[cursorPosition.y]->getString().toWideString().back() == '\n') ? lines[cursorPosition.y]->getString().toWideString().size() - 1 : lines[cursorPosition.y]->getString().toWideString().size();
            cursorPosition.x = last_character_index;

        }
    }

    setCursorPosition(cursorPosition);
}

void setCursorRight() {
    //std::cout << "Right" << "\n";

    if (lines.empty()) {
        return;
    }

    int last_character_index = (lines[cursorPosition.y]->getString().toWideString().back() == '\n') ? lines[cursorPosition.y]->getString().toWideString().size() - 1 : lines[cursorPosition.y]->getString().toWideString().size();

    if (cursorPosition.x < last_character_index) { //////// +1
        cursorPosition.x += 1;
    }
    else {
        if (cursorPosition.y < lines.size() - 1) {
            cursorPosition.x = 0;
            cursorPosition.y += 1;
        }
    }

    setCursorPosition(cursorPosition);
}

void setCursorUp() {
    //std::cout << "Up" << "\n";
    if(lines.empty())
        return;

    if (cursorPosition.y > 0) {

        float targetX = cursor.getGlobalBounds().left;

        cursorPosition.y -= 1;
        sf::Text* line = lines[cursorPosition.y];
        size_t lineLength = line->getString().toWideString().size();

        size_t closestIndex = 0;
        float closestDistance = std::abs(line->findCharacterPos(0).x - targetX);

        for (size_t i = 1; i <= lineLength; ++i) {
            sf::Vector2f pos = line->findCharacterPos(i);
            float distance = std::abs(pos.x - targetX);

            if (distance < closestDistance) {
                closestIndex = i;
                closestDistance = distance;
            }
        }

        cursorPosition.x = closestIndex;
        cursor.setPosition(line->findCharacterPos(closestIndex));

    }
}
void setCursorDown() {
    //std::cout << "Down << "\n";
    if (lines.empty())
        return;

    if (cursorPosition.y < lines.size() - 1) {

        float targetX = cursor.getGlobalBounds().left;

        cursorPosition.y += 1;
        sf::Text* line = lines[cursorPosition.y];
        size_t lineLength = line->getString().toWideString().size();

        size_t closestIndex = 0;
        float closestDistance = std::abs(line->findCharacterPos(0).x - targetX);

        for (size_t i = 1; i <= lineLength; ++i) {
            sf::Vector2f pos = line->findCharacterPos(i);
            float distance = std::abs(pos.x - targetX);

            if (distance < closestDistance) {
                closestIndex = i;
                closestDistance = distance;
            }
        }

        cursorPosition.x = closestIndex;
        cursor.setPosition(line->findCharacterPos(closestIndex));
    }

}

void setCursorLeftWithShift() {

    //std::cout << "shift + Left" << "\n";

    if (lines.empty()) {
        return;
    }
        

    int index = getCursorIndex(cursorPosition) - 1;

    if (selection == nullptr) {
        selection = new Selection();
        selection->start_index = index + 1;
        selection->end_index = index;

    }
    else {
        selection->end_index = index;

        if (selection->end_index == selection->start_index) {
            delete selection;
            selection = nullptr;
        }
    }

    setCursorPosition(getCursorFromIndex(index));
   
}

void setCursorRightWithShift() {
    //std::cout << "shift + Right" << "\n";

    if (lines.empty()) {
        return;
    }

    int index = getCursorIndex(cursorPosition) + 1;

    if (selection == nullptr) {
        selection = new Selection();

        selection->start_index = index - 1;
        selection->end_index = index;

    }
    else {
        selection->end_index = index;

        if (selection->end_index == selection->start_index) {
            delete selection;
            selection = nullptr;
        }
    }

    setCursorPosition(getCursorFromIndex(index));
}

void setCursorUpWithShift() {
    //std::cout << "shift + Up" << "\n";
    if (lines.empty()) {
        return;
    }

    if (selection == nullptr) {

        int prev_index = getCursorIndex(cursorPosition);
        setCursorUp();
        int index = getCursorIndex(cursorPosition);

        selection = new Selection();

        selection->start_index = prev_index;
        selection->end_index = index;

        setCursorPosition(getCursorFromIndex(index));

    }
    else {
        setCursorUp();
        int index = getCursorIndex(cursorPosition);
        selection->end_index = index;

        if (selection->end_index == selection->start_index) {
            delete selection;
            selection = nullptr;
        }

        setCursorPosition(getCursorFromIndex(index));
    }
}

void setCursorDownWithShift() {
    //std::cout << "shift + Down" << "\n";
    if (lines.empty()) {
        return;
    }

    if (selection == nullptr) {

        int prev_index = getCursorIndex(cursorPosition);
        setCursorDown();
        int index = getCursorIndex(cursorPosition);

        selection = new Selection();

        selection->start_index = prev_index;
        selection->end_index = index;

        setCursorPosition(getCursorFromIndex(index));

    }
    else {
        setCursorDown();
        int index = getCursorIndex(cursorPosition);
        selection->end_index = index;

        if (selection->end_index == selection->start_index) {
            delete selection;
            selection = nullptr;
        }

        setCursorPosition(getCursorFromIndex(index));
    }
}

void generateScrollbar() {

    float scrollbar_value;

    std::cout << "cur: " << cursorPosition.y << "\n";

    if (scrollbar != nullptr) {

        float min_val_on_screen = scrollbar->scroll_value;
        int lines_on_screen = int(window->getSize().y / font.getLineSpacing(characterSize));
        float max_val_on_screen = min_val_on_screen + lines_on_screen;

        std::cout << "min: " << min_val_on_screen << "\n";
        std::cout << "lines on screen: " << lines_on_screen << "\n";
        std::cout << "max: " << max_val_on_screen << "\n";
        

        if (cursorPosition.y < min_val_on_screen)
            scrollbar_value = cursorPosition.y;
        else if (cursorPosition.y > max_val_on_screen - 1)
            scrollbar_value = cursorPosition.y - int(window->getSize().y / font.getLineSpacing(characterSize) - 2);
        else
            scrollbar_value = scrollbar->scroll_value;
    }
    else
        scrollbar_value = 0;

    std::cout << "val: " << scrollbar_value << "\n\n\n";

    sf::Vector2f scrollbar_size(16, window->getSize().y);
    sf::Vector2f scrollbar_position(window->getSize().x-16, 0);

    float scrollbar_len = window->getSize().y/font.getLineSpacing(characterSize);
    float max_value = (lines.empty())? 0 : lines.size()-1;

    scrollbar = new Scrollbar(scrollbar_size, scrollbar_position, 0, max_value, scrollbar_value, scrollbar_len);
    scrollbar->onclick_func = []() {

        linesPositioning();
        setCursorPosition(cursorPosition);
    };
}

int main()
{
    
    

    font.loadFromFile("C:/Windows/Fonts/arial.ttf");
    characterSize = 17;
    
    text = L"";

    

    lines = wrap_text(window->getSize().x-16, text);
    generateScrollbar();

    cursor = sf::RectangleShape(sf::Vector2f(2, characterSize));
    cursor.setFillColor(sf::Color::Red);


    sf::Clock clock;

    SFML_intro* intro = new SFML_intro(window);
    delete intro;

    selection = nullptr;

    while (window->isOpen())
    {

        mousePosition = sf::Mouse::getPosition(*window); // get the mouse position about window
        worldMousePosition = window->mapPixelToCoords(mousePosition); // get global mouse position

        currentTime = timeClock.getElapsedTime();

        scrollbar->update();

        sf::Event event;
        while (window->pollEvent(event)) {

            if (event.type == sf::Event::Closed)
                window->close();

            if (event.type == sf::Event::Resized)
            {
                
                // Aktualizacja widoku bez skalowania
                sf::View view;
                view.setSize(static_cast <float>(event.size.width), static_cast <float>(event.size.height));
                view.setCenter(view.getSize() / 2.f);
                window->setView(view);
            }
            
            scrollbar->handleEvent(event);
            
            if (elementGUIClicked != nullptr) {
                mousePress = false;

                if (event.type == sf::Event::MouseButtonReleased && event.mouseButton.button == sf::Mouse::Left) {
                    elementGUIClicked = nullptr;
                }
            }
            else if(elementGUIClicked == nullptr) {
                if (event.type == sf::Event::MouseButtonPressed && event.mouseButton.button == sf::Mouse::Left) {

                    mousePress = true;

                    sf::Vector2i cur_pos = getCursorPosition();

                    if (!lines.empty() && cur_pos.y < lines.size()) {
                        if (selection != nullptr)
                            delete selection;

                        selection = new Selection();
                        selection->start_index = getCursorIndex(cur_pos);
                        selection->end_index = selection->start_index;
                        setCursorPosition(cur_pos);
                    }
                }
                else if (event.type == sf::Event::MouseButtonReleased && event.mouseButton.button == sf::Mouse::Left) {
                    sf::Vector2i cur_pos = getCursorPosition();
                    setCursorPosition(cur_pos);
                    mousePress = false;
                }
                else if (event.type == sf::Event::MouseMoved) {
                    if (mousePress) {
                        sf::Vector2i cur_pos = getCursorPosition();

                        if (selection != nullptr)
                            selection->end_index = getCursorIndex(cur_pos);

                        setCursorPosition(cur_pos);
                    }
                }
            }
            
            if (event.type == sf::Event::KeyPressed && event.key.control && event.key.code == sf::Keyboard::V) {
                // Ctrl + V 
                int index = getCursorIndex(cursorPosition);
                
                std::wstring clip_text = sf::Clipboard::getString().toWideString();
                while (clip_text.find(L"\r\n") != std::wstring::npos) {
                    clip_text.erase(clip_text.find(L"\r\n"), 1);
                };

                text.insert(index, clip_text);
                index += clip_text.size();

                for (auto& line : lines)
                    delete line;

                lines = wrap_text(window->getSize().x - 16, text);
                cursorPosition = getCursorFromIndex(index);

                generateScrollbar();
                linesPositioning();
                setCursorPosition(cursorPosition);
                
            }
            else if (event.type == sf::Event::KeyPressed && event.key.control && event.key.code == sf::Keyboard::C) {
                // Ctrl + C
                if (selection && selection->start_index != selection->end_index) {
                    
                    std::wstring clip_text = text.substr(std::min(selection->start_index, selection->end_index), std::abs(selection->end_index - selection->start_index));
                    sf::Clipboard::setString(clip_text);
                }
            }
            else if (event.type == sf::Event::KeyPressed && event.key.control && event.key.code == sf::Keyboard::X) {
                // Ctrl + X
                if (selection!=nullptr && selection->start_index != selection->end_index) {

                    std::wstring clip_text = text.substr(std::min(selection->start_index, selection->end_index), std::abs(selection->end_index - selection->start_index));
                    sf::Clipboard::setString(clip_text);

                    text.erase(std::min(selection->start_index, selection->end_index), std::abs(selection->end_index - selection->start_index));
                    int index = std::min(selection->start_index, selection->end_index);
                    delete selection;
                    selection = nullptr;
                    
                    generateScrollbar();
                    linesPositioning();
                    setCursorPosition(getCursorFromIndex(index));

                }
            }
            else if (event.type == sf::Event::KeyPressed && event.key.shift && event.key.code == sf::Keyboard::Left) {
                generateScrollbar();
                linesPositioning();
                setCursorLeftWithShift();
            }
            else if (event.type == sf::Event::KeyPressed && event.key.shift && event.key.code == sf::Keyboard::Right) {

                generateScrollbar();
                linesPositioning();
                setCursorRightWithShift();

            }
            else if (event.type == sf::Event::KeyPressed && event.key.shift && event.key.code == sf::Keyboard::Up) {
                
                generateScrollbar();
                linesPositioning();
                setCursorUpWithShift();


                
            }
            else if (event.type == sf::Event::KeyPressed && event.key.shift && event.key.code == sf::Keyboard::Down) {
                generateScrollbar();
                linesPositioning();
                setCursorDownWithShift();

            }
            else if (event.type == sf::Event::KeyPressed && event.key.code == sf::Keyboard::Delete) {
                if (!text.empty()) {

                    if (selection == nullptr || (selection != nullptr && selection->start_index == selection->end_index)) {
                        int index = getCursorIndex(cursorPosition);
                        text.erase(index, 1);
                    }
                    else {
                        text.erase(std::min(selection->start_index, selection->end_index), std::abs(selection->end_index - selection->start_index));
                        int index = std::min(selection->start_index, selection->end_index);
                        delete selection;
                        selection = nullptr;
                        setCursorPosition(getCursorFromIndex(index));
                    }

                    for (auto& line : lines)
                        delete line;

                    lines = wrap_text(window->getSize().x - 16, text);
                    generateScrollbar();
                    linesPositioning();

                }
            }
            else if (event.type == sf::Event::KeyPressed && event.key.code == sf::Keyboard::Left) {
                
                generateScrollbar();
                linesPositioning();
                setCursorLeft();
                if (selection != nullptr) {
                    delete selection;
                    selection = nullptr;
                }
            }
            else if (event.type == sf::Event::KeyPressed && event.key.code == sf::Keyboard::Right) {
                
                generateScrollbar();
                linesPositioning();
                setCursorRight();
                if (selection != nullptr) {
                    delete selection;
                    selection = nullptr;
                }
            }
            else if (event.type == sf::Event::KeyPressed && event.key.code == sf::Keyboard::Up) {
                
                generateScrollbar();
                linesPositioning();
                setCursorUp();
                if (selection != nullptr) {
                    delete selection;
                    selection = nullptr;
                }
            }
            else if (event.type == sf::Event::KeyPressed && event.key.code == sf::Keyboard::Down) {
                
                generateScrollbar();
                linesPositioning();
                setCursorDown();
                if (selection != nullptr) {
                    delete selection;
                    selection = nullptr;
                }
            }
            else if (event.type == sf::Event::TextEntered) {
                
                int index = getCursorIndex(cursorPosition);

                if (event.text.unicode == 8) {
                    // backspace
                    if (index > 0 && !text.empty()) {
                        if (selection == nullptr || (selection!=nullptr && selection->start_index == selection->end_index)) {
                            text.erase(index - 1, 1);
                            index -= 1;
                        }
                        else {
                            text.erase(std::min(selection->start_index, selection->end_index), std::abs(selection->end_index - selection->start_index));
                            index = std::min(selection->start_index, selection->end_index);
                        }

                        if (selection != nullptr) {
                            delete selection;
                            selection = nullptr;
                        }
                    }
                }
                else if (event.text.unicode == 13) {
                    // enter
                    text.insert(index, 1, L'\n');
                    index += 1;

                }
                else if (event.text.unicode == 9) {
                    // tab
                    text.insert(index, 1, L'\t');
                    index += 1;

                }
                else {
                    // other character
                    wchar_t character = static_cast<wchar_t>(event.text.unicode);
                    if (character >= 32 && character != 127) {

                        if (selection != nullptr && selection->start_index != selection->end_index) {

                            text.erase(std::min(selection->start_index, selection->end_index), std::abs(selection->end_index - selection->start_index));
                            index = std::min(selection->start_index, selection->end_index);
                            delete selection;
                            selection = nullptr;
                        }
                        

                        text.insert(index, 1, character);
                        index += 1;
                    }
                }

                if (!lines.empty()) {
                    for (auto& t : lines)
                        delete t;
                }
                lines.clear();

                lines = wrap_text(window->getSize().x - 16, text);

                // Po każdej zmianie kursor wstawiamy po index
                cursorPosition = getCursorFromIndex(index);
                
                generateScrollbar();
                linesPositioning();
                setCursorPosition(cursorPosition);


            }


        }

        window->clear(background_color);

        if (selection != nullptr) {
            selection->draw();
        }

        for (auto& line : lines)
            window->draw(*line);

        if (std::fmod(currentTime.asSeconds(), 0.6f) < 0.3f)
            window->draw(cursor);

        scrollbar->draw();

        window->display();
    }
}
spartanPAGE
  • Rejestracja: dni
  • Ostatnio: dni
2

No pewnie! Co by się nie działo, zawsze zaczynasz w takiej kolejności:

Kopiuj
// Przed pętlą:
generateScrollbar(); // na początek da 0
...
//w pętli:
generateScrollbar(); // w pierwszej pętli znowu da 0
setCursorUp/Right/Etc() // dopiero cokolwiek się zmienia

Zakładając minimalną ingerencję w kod, możesz przygotować generateScrollbar tak, by nie musieć wywoływać jej przed pętlą.
Powodzenia!

tBane
  • Rejestracja: dni
  • Ostatnio: dni
  • Lokalizacja: Poznań
  • Postów: 539
0

Ok, dzięki za odpowiedź. Już poprawiłem. :-) Jeszcze tylko jeden problem mam do rozwiązania. Po enterach źle oblicza cursorPosition.y

Kopiuj
// ...
else if (event.text.unicode == 13) {
    // enter
    text.insert(index, 1, L'\n');
    index += 1;

}

// ...

lines = wrap_text(window->getSize().x - 16, text);

// Po każdej zmianie kursor wstawiamy po index
cursorPosition = getCursorFromIndex(index);
                
generateScrollbar();
linesPositioning();
setCursorPosition(cursorPosition);
// ...
Manna5
  • Rejestracja: dni
  • Ostatnio: dni
  • Lokalizacja: Kraków
  • Postów: 667
1

Może to nie jest sedno tego problemu, ale ten warunek w linii 865 jest dziwny:

Kopiuj
                        if (selection == nullptr || (selection!=nullptr && selection->start_index == selection->end_index)) {

Przecież to jest równoważne prostszemu selection == nullptr || selection->start_index == selection->end_index. Druga część warunku (w nawiasach) nawet nie jest ewaluowana gdy selection jest równe nullptr ze względu na early exit.

tBane
  • Rejestracja: dni
  • Ostatnio: dni
  • Lokalizacja: Poznań
  • Postów: 539
0

Dobra udało się, trzeba było poprawić kod w dwóch miejscach.

Po 1. Należy poprawić funkcję odpowiedzialną za pozycjonowanie kursora:

Kopiuj
void setCursorPosition(sf::Vector2i cursor_position) {
    cursorPosition = cursor_position;

    if (cursor_position == sf::Vector2i(0, 0)) {
        cursor.setPosition(sf::Vector2f(0, 0));
        return;
    }

    if (lines.empty()) {
        cursor.setPosition(sf::Vector2f(0, 0));
        return;
    }


    std::wstring line = (cursorPosition.y < lines.size()) ? lines[cursorPosition.y]->getString().toWideString() : L"";
    
    if (line.size() == 0) {
        sf::Vector2f charPos(0, (cursorPosition.y - scrollbar->scroll_value) * font.getLineSpacing(characterSize));
        cursor.setPosition(charPos);
        return;
    }
    
    if (cursor_position.x <= line.size()) {
        sf::Vector2f charPos = lines[cursorPosition.y]->findCharacterPos(cursor_position.x);
        std::cout << charPos.x << ", " << charPos.y << "\n";
        cursor.setPosition(charPos);
        return;
    }

    sf::Vector2f endPos = lines[cursorPosition.y]->findCharacterPos(line.size());
    cursor.setPosition(endPos);

}

Po 2. Trzeba poprawić fragment kodu odpowiedzialny za dodawanie znaków do tekstu

Kopiuj
else if (event.type == sf::Event::TextEntered) {
    
    int index = getCursorIndex(cursorPosition);

    if (event.text.unicode == 8) {
        // backspace
        if (index > 0 && !text.empty()) {
            if (selection == nullptr || selection->start_index == selection->end_index){
                text.erase(index - 1, 1);
                index -= 1;
            }
            else {
                text.erase(std::min(selection->start_index, selection->end_index), std::abs(selection->end_index - selection->start_index));
                index = std::min(selection->start_index, selection->end_index);
            }

            if (selection != nullptr) {
                delete selection;
                selection = nullptr;
            }
        }

        if (!lines.empty()) {
            for (auto& t : lines)
                delete t;
        }
        lines.clear();

        lines = wrap_text(window->getSize().x - 16, text);

        // Po każdej zmianie kursor wstawiamy po index
        cursorPosition = getCursorFromIndex(index);

        generateScrollbar();
        linesPositioning();
        setCursorPosition(cursorPosition);
    }
    else if (event.text.unicode == 13) {
        // enter
        text.insert(index, 1, L'\n');
        cursorPosition.x = 0;
        cursorPosition.y += 1;

        if (!lines.empty()) {
            for (auto& t : lines)
                delete t;
        }
        lines.clear();

        lines = wrap_text(window->getSize().x - 16, text);

        generateScrollbar();
        linesPositioning();
        setCursorPosition(cursorPosition);

    }
    else if (event.text.unicode == 9) {
        // tab
        text.insert(index, 1, L'\t');
        index += 1;

        if (!lines.empty()) {
            for (auto& t : lines)
                delete t;
        }
        lines.clear();

        lines = wrap_text(window->getSize().x - 16, text);

        // Po każdej zmianie kursor wstawiamy po index
        cursorPosition = getCursorFromIndex(index);

        generateScrollbar();
        linesPositioning();
        setCursorPosition(cursorPosition);

    }
    else {
        // other character
        wchar_t character = static_cast<wchar_t>(event.text.unicode);
        if (character >= 32 && character != 127) {

            if (selection != nullptr && selection->start_index != selection->end_index) {

                text.erase(std::min(selection->start_index, selection->end_index), std::abs(selection->end_index - selection->start_index));
                index = std::min(selection->start_index, selection->end_index);
                delete selection;
                selection = nullptr;
            }
            

            text.insert(index, 1, character);
            index += 1;

            if (!lines.empty()) {
                for (auto& t : lines)
                    delete t;
            }
            lines.clear();

            lines = wrap_text(window->getSize().x - 16, text);

            // Po każdej zmianie kursor wstawiamy po index
            cursorPosition = getCursorFromIndex(index);

            generateScrollbar();
            linesPositioning();
            setCursorPosition(cursorPosition);
        }
    }
}

Zarejestruj się i dołącz do największej społeczności programistów w Polsce.

Otrzymaj wsparcie, dziel się wiedzą i rozwijaj swoje umiejętności z najlepszymi.