Panel użytkownika
Nazwa użytkownika:
Hasło:
Nie masz jeszcze konta?

[SFML 2.X] Notepad v2 - aplikacja notatnik wersja druga

Ostatnio zmodyfikowano 2025-06-07 14:37
Autor Wiadomość
tBane
Temat założony przez niniejszego użytkownika
[SFML 2.X] Notepad v2 - aplikacja notatnik wersja druga
» 2025-06-03 18:28:45
Witam. Postanowiłem od nowa napisać aplikację Notepad, ponieważ w poprzedniej wersji źle pozycjonowałem kursor. Aby to naprawić, musiałem zrezygnować ze zmiennej int index i zamiast niej użyć sf::Vector2i cursorPosition. Skoro usunąłem indeks, wygodniej jest przechowywać tekst w liniach – za pomocą sf::Text. Napisałem już większą część aplikcji.
No więc mój problem polega na tym, że nie wiem jak powinien zachować się program w przypadku podania backspace n początku linii. Próbowałem wzorować się na Microsoft Notepad i raczej wrapowanie całego tekstu odpada, ponieważ czasami słowo z poprzedniej linii się cofa i łączy z tym przed którym zrobiliśmy backspace. Pomoże ktoś i wyjaśni jak powinien zachować się tekst po wciśnięciu backspace na początku linii?


C/C++
#include <SFML/Graphics.hpp>
#include <iostream>
#include <vector>
#include <filesystem>

sf::RenderWindow * window;

sf::Font font;
short characterSize;
sf::Color textColor;
sf::Color backgroundColor;

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

sf::Vector2i mousePosition;
sf::Vector2f worldMousePosition;

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

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

void wrap_text( std::wstring text ) {
   
   
if( !lines.empty() ) {
       
for( auto & line: lines )
           
 delete line;
       
       
lines.clear();
   
}
   
   
///////////////////////////////////
   
   
std::wstring line = L"";
   
std::wstring word = L"";
   
   
std::cout << window->getSize().x << "\n";
   
   
for( auto & character: text ) {
       
       
       
if( character == L'\n' ) {
           
           
if( sf::Text( line + word, font, characterSize ).getGlobalBounds().width > window->getSize().x ) {
               
lines.push_back( new sf::Text( line, font, characterSize ) );
               
line = word;
               
word = L"";
           
}
           
else {
               
lines.push_back( new sf::Text( line + word, font, characterSize ) );
               
line = L"";
               
word = L"";
           
}
           
        }
       
else if( character == L' ' || character == L'\t' ) {
           
           
if( sf::Text( line + word, font, characterSize ).getGlobalBounds().width > window->getSize().x ) {
               
lines.push_back( new sf::Text( line, font, characterSize ) );
               
line = word + character;
               
word = L"";
           
}
           
else {
               
line = line + word + character;
               
word = L"";
           
}
           
        }
       
else
           
 word = word + character;
       
       
   
}
   
   
if( line != L"" || word != L"" ) {
       
       
lines.push_back( new sf::Text( line + word, font, characterSize ) );
   
}
   
   
for( int i = 0; i < lines.size(); i++ ) {
       
lines[ i ]->setPosition( sf::Vector2f( 0, i * font.getLineSpacing( characterSize ) ) );
       
lines[ i ]->setFillColor( textColor );
       
   
}
   
}

void setCursorUp() {
   
   
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() {
   
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 cursorPositioning() {
   
   
if( lines.size() == 0 ) {
       
cursor.setPosition( 0, 0 );
       
return;
   
}
   
   
float line_length = lines[ cursorPosition.y ]->getString().toWideString().size();
   
   
sf::Vector2f pos;
   
pos.x = lines[ cursorPosition.y ]->findCharacterPos( cursorPosition.x ).x;
   
pos.y = cursorPosition.y * font.getLineSpacing( characterSize );
   
cursor.setPosition( pos );
}




int main()
{
   
   
sf::View view( sf::FloatRect( 0, 0, 480, 640 ) );
   
window = new sf::RenderWindow( sf::VideoMode( view.getSize().x, view.getSize().y ), "Easy Notepad v2", sf::Style::Titlebar | sf::Style::Close );
   
   
font = sf::Font();
   
font.loadFromFile( "arial.ttf" );
   
   
characterSize = 17;
   
   
textColor = sf::Color( 192, 192, 192 );
   
backgroundColor = sf::Color( 48, 48, 48 );
   
   
wrap_text(
   
L"Gracz najpierw zagaduje handlarza gdyż ten jest najbliżej. Handlarz oferuje skórzane ubranie w zamian za dostarczenie kilku skór od myśliwego, "
    L"którego gracz mijał wcześniej. Zielarka da graczowi trochę złota w zamian za przyniesienie kilku roślin leczniczych. "
    L"U kowala gracz może zakupić oręż - zwyczajny prosty miecz gdyż jest to niewprawiony kowal w miecznictwie. "
    L"Zaś do wieży mędrca nie da się dostać. Gracz rusza spowrotem do myśliwego po skóry, lecz ten jest nieufny, "
    L"ale ostatecznie zgadza się i daje graczowi skóry.\n"
    L"Gracz wraca ze skórami do handlarza i odbiera nowe ubranie \"skórzane kurtka\" oraz \"skórzane spodnie\"."
    L"Handlarz jednak jeszcze jedno zadanie ma dla gracza. Dostawa towarów ze wschodu się opóźnia i trzeba sprawdzić "
    L"co się z nią stało i tak gracz rusza z kolejnym zadaniem \"spóźniona dostawa\"."
   
);
   
   
std::cout << "Current directory: " << std::filesystem::current_path() << std::endl;
   
   
cursor = sf::RectangleShape( sf::Vector2f( 2, characterSize ) );
   
cursor.setFillColor( sf::Color::Red );
   
   
sf::Clock clock;
   
   
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();
       
       
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 );
           
}
           
else if( event.type == sf::Event::MouseButtonReleased && event.mouseButton.button == sf::Mouse::Left ) {
               
//sf::Vector2i cur_pos = getCursorPosition();
                //setCursorPosition(cur_pos);
           
}
           
else if( event.type == sf::Event::TextEntered ) {
               
               
if( event.text.unicode < 128 ) {
                   
                   
std::wstring line = lines[ cursorPosition.y ]->getString().toWideString();
                   
                   
if( event.text.unicode == '\b' ) {
                       
// backspace
                       
if( line.size() > 0 && cursorPosition != sf::Vector2i( 0, 0 ) ) {
                           
if( cursorPosition.x > 0 ) {
                               
line.erase( cursorPosition.x - 1, 1 );
                               
cursorPosition.x -= 1;
                           
}
                           
else {
                               
// jak powinniem zachowac się tekst ?
                           
}
                           
                        }
                       
                    }
                   
else if( event.text.unicode == 32 ) {
                       
// space
                       
line.insert( cursorPosition.x, 1, ' ' );
                       
cursorPosition.x += 1;
                   
}
                   
else if( event.text.unicode == 13 ) {
                       
// enter
                       
line.insert( cursorPosition.x, 1, '\n' );
                       
cursorPosition.x += 1;
                       
                   
}
                   
else {
                       
// is character
                       
line.insert( cursorPosition.x, 1, char( event.text.unicode ) );
                       
lines[ cursorPosition.y ]->setString( line );
                       
cursorPosition.x += 1;
                   
}
                   
                   
lines[ cursorPosition.y ]->setString( line );
               
}
               
               
cursorPositioning();
           
}
           
else if( event.type == sf::Event::KeyPressed ) {
               
if( event.key.code == sf::Keyboard::Left ) {
                   
if( cursorPosition.x > 0 )
                       
 cursorPosition.x -= 1;
                   
else if( cursorPosition.y > 0 ) {
                       
cursorPosition.y -= 1;
                       
cursorPosition.x = lines[ cursorPosition.y ]->getString().toWideString().size();
                   
}
                   
                }
               
else if( event.key.code == sf::Keyboard::Right ) {
                   
if( cursorPosition.x < lines[ cursorPosition.y ]->getString().getSize() )
                       
 cursorPosition.x += 1;
                   
else if( cursorPosition.y < lines.size() - 1 ) {
                       
cursorPosition.x = 0;
                       
cursorPosition.y += 1;
                   
}
                   
                }
               
else if( event.key.code == sf::Keyboard::Up ) {
                   
setCursorUp();
                   
               
}
               
else if( event.key.code == sf::Keyboard::Down ) {
                   
                   
setCursorDown();
               
}
               
               
cursorPositioning();
               
//setCursorPosition(cursorPosition);
               
           
}
           
           
        }
       
       
window->clear( backgroundColor );
       
for( auto & line: lines )
           
 window->draw( * line );
       
       
if( std::fmod( currentTime.asSeconds(), 0.6f ) < 0.3f )
           
 window->draw( cursor );
       
       
window->display();
   
}
}
P-182436
tBane
Temat założony przez niniejszego użytkownika
» 2025-06-03 19:51:24
Napisałem taki Backspace ale też nie działa. Źle pozycjonuje linie po enterze:


C/C++
if( event.text.unicode == '\b' ) {
   
// backspace
   
if( line.size() > 0 && cursorPosition != sf::Vector2i( 0, 0 ) ) {
       
if( cursorPosition.x > 0 && cursorPosition.y > 0 ) {
           
std::wstring prev_line = lines[ cursorPosition.y - 1 ]->getString().toWideString();
           
std::wstring current_line = lines[ cursorPosition.y ]->getString().toWideString();
           
           
std::vector < sf::Text * > new_lines = wrap_text( prev_line + current_line );
           
           
// usuń stare obiekty tekstowe
           
delete lines[ cursorPosition.y - 1 ];
           
delete lines[ cursorPosition.y ];
           
           
// przypisz nowe
           
lines[ cursorPosition.y - 1 ] = new_lines[ 0 ];
           
lines[ cursorPosition.y ] = new_lines[ 1 ];
           
       
}
       
    }
   
}
P-182437
termistor
» 2025-06-03 20:00:56
Funkcja wrap_text w przykładzie, który wkleiłeś, zwraca void i tylko ustawia obiekty lines na bazie podanej w całości treści. Kiedy w metodzie obsługi Backspace próbowałeś wywołać:


std::vector<sf::Text*> new_lines = wrap_text(prev_line + current_line);

to ani nie zwracałeś niczego z wrap_text, ani nie aktualizowałeś globalnego documentText. Dlatego nic się nie zmieniało albo linie były źle przeliczane
P-182439
tBane
Temat założony przez niniejszego użytkownika
» 2025-06-03 20:02:38
Mój błąd zapomniałem dodać, że zmieniłem funkcję wrap_text i teraz zwraca listę std::vector < st::Text* >. Przesuwa mi linię w dół ale pozostałych linii już nie. Nie wiem dlaczego.

C/C++
#include <SFML/Graphics.hpp>
#include <iostream>
#include <vector>
#include <filesystem>

sf::RenderWindow * window;

sf::Font font;
short characterSize;
sf::Color textColor;
sf::Color backgroundColor;

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

sf::Vector2i mousePosition;
sf::Vector2f worldMousePosition;

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

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

std::vector < sf::Text * > wrap_text( std::wstring text ) {
   
   
std::vector < sf::Text * > lines;
   
   
std::wstring line = L"";
   
std::wstring word = L"";
   
   
std::cout << window->getSize().x << "\n";
   
   
for( auto & character: text ) {
       
       
       
if( character == L'\n' ) {
           
           
if( sf::Text( line + word, font, characterSize ).getGlobalBounds().width > window->getSize().x ) {
               
lines.push_back( new sf::Text( line, font, characterSize ) );
               
line = word;
               
word = L"";
           
}
           
else {
               
lines.push_back( new sf::Text( line + word, font, characterSize ) );
               
line = L"";
               
word = L"";
           
}
           
        }
       
else if( character == L' ' || character == L'\t' ) {
           
           
if( sf::Text( line + word, font, characterSize ).getGlobalBounds().width > window->getSize().x ) {
               
lines.push_back( new sf::Text( line, font, characterSize ) );
               
line = word + character;
               
word = L"";
           
}
           
else {
               
line = line + word + character;
               
word = L"";
           
}
           
        }
       
else
           
 word = word + character;
       
       
   
}
   
   
if( line != L"" || word != L"" ) {
       
       
lines.push_back( new sf::Text( line + word, font, characterSize ) );
   
}
   
   
for( int i = 0; i < lines.size(); i++ ) {
       
lines[ i ]->setPosition( sf::Vector2f( 0, i * font.getLineSpacing( characterSize ) ) );
       
lines[ i ]->setFillColor( textColor );
       
   
}
   
   
return lines;
   
}

void setCursorUp() {
   
   
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() {
   
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 cursorPositioning() {
   
   
if( lines.size() == 0 ) {
       
cursor.setPosition( 0, 0 );
       
return;
   
}
   
   
float line_length = lines[ cursorPosition.y ]->getString().toWideString().size();
   
   
sf::Vector2f pos;
   
pos.x = lines[ cursorPosition.y ]->findCharacterPos( cursorPosition.x ).x;
   
pos.y = cursorPosition.y * font.getLineSpacing( characterSize );
   
cursor.setPosition( pos );
}




int main()
{
   
   
sf::View view( sf::FloatRect( 0, 0, 480, 640 ) );
   
window = new sf::RenderWindow( sf::VideoMode( view.getSize().x, view.getSize().y ), "Easy Notepad v2", sf::Style::Titlebar | sf::Style::Close );
   
   
font = sf::Font();
   
font.loadFromFile( "arial.ttf" );
   
   
characterSize = 17;
   
   
textColor = sf::Color( 192, 192, 192 );
   
backgroundColor = sf::Color( 48, 48, 48 );
   
   
lines = wrap_text(
   
L"Gracz najpierw zagaduje handlarza gdyż ten jest najbliżej. Handlarz oferuje skórzane ubranie w zamian za dostarczenie kilku skór od myśliwego, "
    L"którego gracz mijał wcześniej. Zielarka da graczowi trochę złota w zamian za przyniesienie kilku roślin leczniczych. "
    L"U kowala gracz może zakupić oręż - zwyczajny prosty miecz gdyż jest to niewprawiony kowal w miecznictwie. "
    L"Zaś do wieży mędrca nie da się dostać. Gracz rusza spowrotem do myśliwego po skóry, lecz ten jest nieufny, "
    L"ale ostatecznie zgadza się i daje graczowi skóry.\n"
    L"Gracz wraca ze skórami do handlarza i odbiera nowe ubranie \"skórzane kurtka\" oraz \"skórzane spodnie\"."
    L"Handlarz jednak jeszcze jedno zadanie ma dla gracza. Dostawa towarów ze wschodu się opóźnia i trzeba sprawdzić "
    L"co się z nią stało i tak gracz rusza z kolejnym zadaniem \"spóźniona dostawa\"."
   
);
   
   
std::cout << "Current directory: " << std::filesystem::current_path() << std::endl;
   
   
cursor = sf::RectangleShape( sf::Vector2f( 2, characterSize ) );
   
cursor.setFillColor( sf::Color::Red );
   
   
sf::Clock clock;
   
   
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();
       
       
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 );
           
}
           
else if( event.type == sf::Event::MouseButtonReleased && event.mouseButton.button == sf::Mouse::Left ) {
               
//sf::Vector2i cur_pos = getCursorPosition();
                //setCursorPosition(cur_pos);
           
}
           
else if( event.type == sf::Event::TextEntered ) {
               
               
if( event.text.unicode < 128 ) {
                   
                   
std::wstring line = lines[ cursorPosition.y ]->getString().toWideString();
                   
                   
if( event.text.unicode == '\b' ) {
                       
// backspace
                       
if( line.size() > 0 && cursorPosition != sf::Vector2i( 0, 0 ) ) {
                           
if( cursorPosition.x > 0 && cursorPosition.y > 0 ) {
                               
std::wstring prev_line = lines[ cursorPosition.y - 1 ]->getString().toWideString();
                               
std::wstring current_line = lines[ cursorPosition.y ]->getString().toWideString();
                               
                               
std::vector < sf::Text * > new_lines = wrap_text( prev_line + L"\n" + current_line );
                               
                               
// usuń stare obiekty tekstowe
                               
delete lines[ cursorPosition.y - 1 ];
                               
delete lines[ cursorPosition.y ];
                               
                               
// przypisz nowe
                               
lines[ cursorPosition.y - 1 ] = new_lines[ 0 ];
                               
lines[ cursorPosition.y ] = new_lines[ 1 ];
                               
                           
}
                           
                        }
                       
                    }
                   
else if( event.text.unicode == 32 ) {
                       
// space
                       
line.insert( cursorPosition.x, 1, ' ' );
                       
cursorPosition.x += 1;
                       
                   
}
                   
else if( event.text.unicode == 13 ) {
                       
// enter
                       
line.insert( cursorPosition.x, 1, '\n' );
                       
cursorPosition.x += 1;
                       
                   
}
                   
else {
                       
// is character
                       
line.insert( cursorPosition.x, 1, char( event.text.unicode ) );
                       
lines[ cursorPosition.y ]->setString( line );
                       
cursorPosition.x += 1;
                   
}
                   
                   
lines[ cursorPosition.y ]->setString( line );
                   
std::wstring text = L"";
                   
for( auto & line: lines )
                       
 text = text + line->getString().toWideString();
                   
                   
wrap_text( text );
               
}
               
               
cursorPositioning();
           
}
           
else if( event.type == sf::Event::KeyPressed ) {
               
if( event.key.code == sf::Keyboard::Left ) {
                   
if( cursorPosition.x > 0 )
                       
 cursorPosition.x -= 1;
                   
else if( cursorPosition.y > 0 ) {
                       
cursorPosition.y -= 1;
                       
cursorPosition.x = lines[ cursorPosition.y ]->getString().toWideString().size();
                   
}
                   
                }
               
else if( event.key.code == sf::Keyboard::Right ) {
                   
if( cursorPosition.x < lines[ cursorPosition.y ]->getString().getSize() )
                       
 cursorPosition.x += 1;
                   
else if( cursorPosition.y < lines.size() - 1 ) {
                       
cursorPosition.x = 0;
                       
cursorPosition.y += 1;
                   
}
                   
                }
               
else if( event.key.code == sf::Keyboard::Up ) {
                   
setCursorUp();
                   
               
}
               
else if( event.key.code == sf::Keyboard::Down ) {
                   
                   
setCursorDown();
               
}
               
               
cursorPositioning();
               
//setCursorPosition(cursorPosition);
               
           
}
           
           
        }
       
       
window->clear( backgroundColor );
       
for( auto & line: lines )
           
 window->draw( * line );
       
       
if( std::fmod( currentTime.asSeconds(), 0.6f ) < 0.3f )
           
 window->draw( cursor );
       
       
window->display();
   
}
}
P-182440
nanoant20
» 2025-06-03 20:09:44
mam kilka uwag co do projektu "Easy-Notepad" umieszczonego na github
ponieważ zamknąłeś temat [cmake] Jak napisać cmake ?
zrobię trochę off-topic , możesz to zostawić tak, jak jest – Ty decydujesz, co zrobić

ponieważ nie używam MSVS tylko g++ / clang , po użyciu komendy konfiguracji procesu budowania projektu
cmake .. -G "MinGW Makefiles"
dostaje error:


\Easy-Notepad-main\EasyNotepad\main.cpp: In function 'int main()':
C:\Users\3195\Downloads\Easy-Notepad-main\EasyNotepad\main.cpp:444:18: error: 'fmod' is not a member of 'std'
  444 |         if (std::fmod(currentTime.asSeconds(), 0.6f) < 0.3f)
      |                  ^~~~

O "holy moly" error: main.cpp:444:18:

w linijce
if( std::fmod( currentTime.asSeconds(), 0.6f ) < 0.3f )


a) w innym wątku poruszyłem temat , że kompilator MSVS dołącza nagłówki w sposób ukryty
error wskazuje na brak biblioteki
< cmath >


b) Wykonujesz porównanie zmiennoprzecinkowe, co jest problematyczne ponieważ liczby zmiennoprzecinkowe posiadają reprezentację przybliżoną

Ponieważ do pisania swoich aplikacji używasz Visual Studio 2022 uważam że powinieneś o tym powiadomić swoich potencjalnych użytkowników, na pewno będzie ta uwaga przydatna przy Twoim 2 projekcie "Editor-RPG2D"

teraz uwagi jeśli chodzi o CMakeList.txt

Jeżeli użytkownik pobrał SFML, a musi to zrobić żeby skompilować sobie program, inaczej nie dołączy, np.
#include <SFML/Graphics.hpp>
   
to po co ten katalog / folder "libs" z .dll'kami sfml'a ?

Sam piszesz w punkcie
2. Pobierz bibliotekę SFML i umieść ją w katalogu C:\SFML-2.6.2
więc biblioteki te powinny być kopiowane z powyższego katalagu / folderu

Osobiście uważam że poniższa część to bardzo zła praktyka. Powoduje, że ten projekt można zbudować tylko na komputerze z identyczną konfigurację jak twoja
Twoje ręczne ustawienie, powinieneś zastąpić ustawiając ścieżkę do katalogu głównego SFML i potem zdefiniować sobie jakąś zmienną, za pomocą której będziesz się odwoływał, np. coś takiego
"${SFML_BIN}/sfml-graphics-d-2.dll"
   


 set(DEBUG_DLLS
 libs/sfml-graphics-d-2.dll
 libs/sfml-system-d-2.dll
 libs/sfml-window-d-2.dll
)

set(RELEASE_DLLS
 libs/sfml-graphics-2.dll
 libs/sfml-system-2.dll
 libs/sfml-window-2.dll
)

# copy files to Release
foreach(ASSET ${RELEASE_DLLS})
    add_custom_command(TARGET ${PROJECT_NAME} POST_BUILD
        COMMAND ${CMAKE_COMMAND} -E make_directory ${CMAKE_BINARY_DIR}/Release
        COMMAND ${CMAKE_COMMAND} -E copy_if_different
            ${CMAKE_SOURCE_DIR}/EasyNotepad/${ASSET}
            ${CMAKE_BINARY_DIR}/Release
        COMMENT "Copying ${ASSET} to Release folder"
        VERBATIM
        CONFIGURATIONS Release
    )
endforeach()

# copy files to Debug
foreach(ASSET ${DEBUG_DLLS})
    add_custom_command(TARGET ${PROJECT_NAME} POST_BUILD
        COMMAND ${CMAKE_COMMAND} -E make_directory ${CMAKE_BINARY_DIR}/Debug
        COMMAND ${CMAKE_COMMAND} -E copy_if_different
            ${CMAKE_SOURCE_DIR}/EasyNotepad/${ASSET}
            ${CMAKE_BINARY_DIR}/Debug
        COMMENT "Copying ${ASSET} to Debug folder"
        VERBATIM
        CONFIGURATIONS Debug
    )
endforeach()

dalej jeżeli chodzi o CMakeList.txt
budując program użytkownik może wybierać / zadecydować czy chce zbudować Release czy Debug

# add the executable
add_executable(${PROJECT_NAME} EasyNotepad/main.cpp)
powyższa linijka decyduje że program buduje się z oknem konsoli cmd , nawet jeżeli uesr będzie budował projekt z flagą
cmake --build . --config Release

dostanie w gratisie okno cmd


dalej, masz tam pętlę, które tworzą katalogi / foldery dla Release i Debug. Trafiają tam dll'ki sfml, czcionka , jest to w porządku , ale sam program "EasyNotepad.exe" chyba już tam nie trafia ? tylko się buduje w katalogu / folderze "build"
Sam "program.exe" nie uruchomi się bez tych dll'ek , chyba że ktoś w systemie dodał SMFL do zmiennej PATH

nie wiem czy działa w MSVS Visual Studio, ale zmień na:

# set the Debugger Working Directory in Visual Studio (Debug/Release)
set_target_properties(${PROJECT_NAME} PROPERTIES
    # VS_DEBUGGER_WORKING_DIRECTORY "${CMAKE_BINARY_DIR}/$<CONFIG>"
    RUNTIME_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/$<CONFIG>"
)

Testowanie oraz debugowanie jest kluczowym elementem i fundamentem pracy programisty , który zapewnia jakość. Zalecam przeprowadzanie dokładnych testów na każdym etapie budowy.










P-182441
tBane
Temat założony przez niniejszego użytkownika
» 2025-06-03 20:16:35
OK. Poprawię cMake jak tylko napiszę Notepad v2. Wtedy ten pierwszy skasuję i zabiorę się za cMake. Szczerze mówiąc to pierwszy raz pisałem cmake i dlatego tak słabo. Napisałem tak jak doradził ChatGPT i widocznie nie jest w tym zbyt dobry ..
Nadal mam problem z backspace (// backspace). Już poprawnie usuwa znak ze środka linii, ale nadal niepoprawnie gdy kasujemy znak z początku linii. Liczę na waszą pomoc :-)

C/C++
#include <SFML/Graphics.hpp>
#include <iostream>
#include <vector>
#include <cmath>
#include <filesystem>

sf::RenderWindow * window;

sf::Font font;
short characterSize;
sf::Color textColor;
sf::Color backgroundColor;

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

sf::Vector2i mousePosition;
sf::Vector2f worldMousePosition;

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

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

std::vector < sf::Text * > wrap_text( std::wstring text ) {
   
   
std::vector < sf::Text * > lines;
   
   
std::wstring line = L"";
   
std::wstring word = L"";
   
   
std::cout << window->getSize().x << "\n";
   
   
for( auto & character: text ) {
       
       
       
if( character == L'\n' ) {
           
           
if( sf::Text( line + word, font, characterSize ).getGlobalBounds().width > window->getSize().x ) {
               
lines.push_back( new sf::Text( line, font, characterSize ) );
               
line = word;
               
word = L"";
           
}
           
else {
               
lines.push_back( new sf::Text( line + word, font, characterSize ) );
               
line = L"";
               
word = L"";
           
}
           
        }
       
else if( character == L' ' || character == L'\t' ) {
           
           
if( sf::Text( line + word, font, characterSize ).getGlobalBounds().width > window->getSize().x ) {
               
lines.push_back( new sf::Text( line, font, characterSize ) );
               
line = word + character;
               
word = L"";
           
}
           
else {
               
line = line + word + character;
               
word = L"";
           
}
           
        }
       
else
           
 word = word + character;
       
       
   
}
   
   
if( line != L"" || word != L"" ) {
       
       
lines.push_back( new sf::Text( line + word, font, characterSize ) );
   
}
   
   
for( int i = 0; i < lines.size(); i++ ) {
       
lines[ i ]->setPosition( sf::Vector2f( 0, i * font.getLineSpacing( characterSize ) ) );
       
lines[ i ]->setFillColor( textColor );
       
   
}
   
   
return lines;
   
}

void setCursorUp() {
   
   
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() {
   
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 cursorPositioning() {
   
   
if( lines.size() == 0 ) {
       
cursor.setPosition( 0, 0 );
       
return;
   
}
   
   
float line_length = lines[ cursorPosition.y ]->getString().toWideString().size();
   
   
sf::Vector2f pos;
   
pos.x = lines[ cursorPosition.y ]->findCharacterPos( cursorPosition.x ).x;
   
pos.y = cursorPosition.y * font.getLineSpacing( characterSize );
   
cursor.setPosition( pos );
}




int main()
{
   
   
sf::View view( sf::FloatRect( 0, 0, 480, 640 ) );
   
window = new sf::RenderWindow( sf::VideoMode( view.getSize().x, view.getSize().y ), "Easy Notepad v2", sf::Style::Titlebar | sf::Style::Close );
   
   
font = sf::Font();
   
font.loadFromFile( "arial.ttf" );
   
   
characterSize = 17;
   
   
textColor = sf::Color( 192, 192, 192 );
   
backgroundColor = sf::Color( 48, 48, 48 );
   
   
lines = wrap_text(
   
L"Gracz najpierw zagaduje handlarza gdyż ten jest najbliżej. Handlarz oferuje skórzane ubranie w zamian za dostarczenie kilku skór od myśliwego, "
    L"którego gracz mijał wcześniej. Zielarka da graczowi trochę złota w zamian za przyniesienie kilku roślin leczniczych. "
    L"U kowala gracz może zakupić oręż - zwyczajny prosty miecz gdyż jest to niewprawiony kowal w miecznictwie. "
    L"Zaś do wieży mędrca nie da się dostać. Gracz rusza spowrotem do myśliwego po skóry, lecz ten jest nieufny, "
    L"ale ostatecznie zgadza się i daje graczowi skóry.\n"
    L"Gracz wraca ze skórami do handlarza i odbiera nowe ubranie \"skórzane kurtka\" oraz \"skórzane spodnie\"."
    L"Handlarz jednak jeszcze jedno zadanie ma dla gracza. Dostawa towarów ze wschodu się opóźnia i trzeba sprawdzić "
    L"co się z nią stało i tak gracz rusza z kolejnym zadaniem \"spóźniona dostawa\"."
   
);
   
   
std::cout << "Current directory: " << std::filesystem::current_path() << std::endl;
   
   
cursor = sf::RectangleShape( sf::Vector2f( 2, characterSize ) );
   
cursor.setFillColor( sf::Color::Red );
   
   
sf::Clock clock;
   
   
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();
       
       
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 );
           
}
           
else if( event.type == sf::Event::MouseButtonReleased && event.mouseButton.button == sf::Mouse::Left ) {
               
//sf::Vector2i cur_pos = getCursorPosition();
                //setCursorPosition(cur_pos);
           
}
           
else if( event.type == sf::Event::TextEntered ) {
               
               
if( event.text.unicode < 128 ) {
                   
                   
std::wstring line = lines[ cursorPosition.y ]->getString().toWideString();
                   
                   
if( event.text.unicode == '\b' ) {
                       
// backspace
                       
if( line.size() > 0 && cursorPosition != sf::Vector2i( 0, 0 ) ) {
                           
if( cursorPosition.x == 0 && cursorPosition.y > 0 ) {
                               
std::wstring prev_line = lines[ cursorPosition.y - 1 ]->getString().toWideString();
                               
std::wstring current_line = lines[ cursorPosition.y ]->getString().toWideString();
                               
                               
std::vector < sf::Text * > new_lines = wrap_text( prev_line + current_line );
                               
                               
// usuń stare obiekty tekstowe
                               
delete lines[ cursorPosition.y - 1 ];
                               
delete lines[ cursorPosition.y ];
                               
                               
// przypisz nowe
                               
lines[ cursorPosition.y - 1 ] = new_lines[ 0 ];
                               
lines[ cursorPosition.y ] = new_lines[ 1 ];
                               
                           
}
                           
else if( cursorPosition.x > 0 ) {
                               
line.erase( cursorPosition.x - 1, 1 );
                               
cursorPosition.x -= 1;
                           
}
                           
                        }
                       
                    }
                   
else if( event.text.unicode == 32 ) {
                       
// space
                       
line.insert( cursorPosition.x, 1, ' ' );
                       
cursorPosition.x += 1;
                       
                   
}
                   
else if( event.text.unicode == 13 ) {
                       
// enter
                       
line.insert( cursorPosition.x, 1, '\n' );
                       
cursorPosition.y += 1;
                       
cursorPosition.x = 0;
                       
                       
                   
}
                   
else {
                       
// is character
                       
line.insert( cursorPosition.x, 1, char( event.text.unicode ) );
                       
lines[ cursorPosition.y ]->setString( line );
                       
cursorPosition.x += 1;
                   
}
                   
                   
lines[ cursorPosition.y ]->setString( line );
                   
std::wstring text = L"";
                   
for( auto & line: lines )
                       
 text = text + line->getString().toWideString() + L"\n";
                   
                   
lines = wrap_text( text );
               
}
               
               
cursorPositioning();
           
}
           
else if( event.type == sf::Event::KeyPressed ) {
               
if( event.key.code == sf::Keyboard::Left ) {
                   
if( cursorPosition.x > 0 )
                       
 cursorPosition.x -= 1;
                   
else if( cursorPosition.y > 0 ) {
                       
cursorPosition.y -= 1;
                       
cursorPosition.x = lines[ cursorPosition.y ]->getString().toWideString().size();
                   
}
                   
                }
               
else if( event.key.code == sf::Keyboard::Right ) {
                   
if( cursorPosition.x < lines[ cursorPosition.y ]->getString().getSize() )
                       
 cursorPosition.x += 1;
                   
else if( cursorPosition.y < lines.size() - 1 ) {
                       
cursorPosition.x = 0;
                       
cursorPosition.y += 1;
                   
}
                   
                }
               
else if( event.key.code == sf::Keyboard::Up ) {
                   
setCursorUp();
                   
               
}
               
else if( event.key.code == sf::Keyboard::Down ) {
                   
                   
setCursorDown();
               
}
               
               
cursorPositioning();
               
//setCursorPosition(cursorPosition);
               
           
}
           
           
        }
       
       
window->clear( backgroundColor );
       
for( auto & line: lines )
           
 window->draw( * line );
       
       
if( std::fmod( currentTime.asSeconds(), 0.6f ) < 0.3f )
           
 window->draw( cursor );
       
       
window->display();
   
}
}
P-182442
termistor
» 2025-06-03 21:36:01
Witaj! Dziękuję za szczegółowy opis problemu. Poniżej znajdziesz analizę i propozycje rozwiązania problemów z Twoim kodem:

1. Problem z backspace przy wierszach
W klasie
TextEditor
 występuje błąd logiki obsługi backspace w przypadku scalania linii. Gdy kursor znajduje się na początku linii (x=0), kod próbuje usunąć poprzednią linię i połączyć ją z bieżącą. Jednak po scaleniu linii, wynikowy wektor
new_lines
 może zawierać więcej niż 2 elementy (jeśli tekst nie mieści się w jednej linii). Obecnie kod próbuje przypisać tylko dwa pierwsze elementy:

lines[cursorPosition.y - 1] = new_lines[0];
lines[cursorPosition.y] = new_lines[1];
To prowadzi do out-of-bounds przy dostępie do
new_lines[1]
, jeśli wektor
new_lines
 ma mniej niż 2 elementy. Proponowane rozwiązanie:
- Zastąp fragment:

lines[cursorPosition.y - 1] = new_lines[0];
lines[cursorPosition.y] = new_lines[1];
- Nowym kodem:

// Usuń stare linie
for (auto& line : lines) {
    delete line;
}
lines.clear();

// Dodaj nowe linie
lines.insert(lines.begin(), new_lines.begin(), new_lines.end());
- Dodatkowo, po scaleniu linii, zaktualizuj pozycję kursora:

cursorPosition.x = 0;
cursorPosition.y = 0;

2. Problem z CMake i SFML
Twój
CMakeLists.txt
 powinien zawierać:

cmake_minimum_required(VERSION 3.10)
project(TextEditor)

find_package(SFML REQUIRED COMPONENTS graphics window system)

add_executable(TextEditor main.cpp)

target_link_libraries(TextEditor SFML::graphics SFML::window SFML::system)
Upewnij się, że:
- SFML jest zainstalowany w systemie (np. przez
apt-get install libsfml-dev
 na Linuxie)
- Zmienna środowiskowa
SFML_DIR
 wskazuje na katalog z plikami cmake SFML (jeśli nie korzystasz z systemowej instalacji)
- Plik
arial.ttf
 znajduje się w tym samym katalogu co wykonywalny program

3. Błąd kompilacji: "undefined reference to 'main'"
Ten błąd oznacza, że kompilator nie znalazł funkcji
main()
. Twoja implementacja zawiera pętlę główną w klasie
TextEditor
, ale brakuje konkretnego
main.cpp
 z funkcją
main()
. Proponowany kod startowy:

#include <SFML/Graphics.hpp>
#include "TextEditor.h"

int main() {
    sf::RenderWindow window(sf::VideoMode(800, 600), "Text Editor");
    TextEditor editor(window);
   
    while (window.isOpen()) {
        sf::Event event;
        while (window.pollEvent(event)) {
            if (event.type == sf::Event::Closed)
                window.close();
        }
       
        editor.handleInput();
        editor.update();
        editor.render(window);
    }
   
    return 0;
}

4. Ulepszenia kodu
- Zarządzanie pamięcią: Obecnie masz wycieki pamięci, ponieważ nie usuwasz wszystkich obiektów
sf::Text*
. Dodaj destruktor do klasy
TextEditor
:

TextEditor::~TextEditor() {
    for (auto* line : lines_) {
        delete line;
    }
}

- Obsługa kursora: Aktualna implementacja nie zaktualizuje pozycji kursora po scaleniu linii. Dodaj po scaleniu linii:

cursorPosition.y = 0;
cursorPosition.x = 0;

- Optymalizacja: Funkcja
wrap_text
 może być wywoływana za często. Zastąp ją aktualizacją tylko zmodyfikowanych linii.

5. Dodatkowe sugestie
- Dodaj obsługę klawiszy strzałek do nawigacji w obrębie linii
- Wprowadź limit szybkości wpisywania (antispam)
- Dodaj zapisywanie i wczytywanie plików
- Ulepsz wygląd kursora (np. zmienna intensywność)

Jeśli potrzebujesz pomocy z konkretnym aspektem działania programu, chętnie pomogę. Pamiętaj, że najlepiej testować zmiany krok po kroku, sprawdzając stan pamięci i poprawność indeksów tablic.
P-182446
tBane
Temat założony przez niniejszego użytkownika
» 2025-06-03 21:41:01
No z tym kasowaniem linii to mi kasuje cały tekst a nie jedną linię :-/
P-182447
« 1 » 2 3
  Strona 1 z 3 Następna strona