4programmers.net

Witaj!

tBane dodał nowy post w wątku: Easy Notepad - Aplikacja Notatnik


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(); } } 


Zobacz post

Z poważaniem,
4programmers.net

Jeżeli masz problemy z kliknięciem na przycisk "Zobacz post", skopiuj i wklej poniższy link w przeglądarce:

http://4programmers.net/Notification?path=%252FForum%252FC_i_C%252B%252B%252F376354-easy_notepad_aplikacja_notatnik%253Fp%253D2001601%2523id2001601