Compare commits

...

3 Commits

Author SHA1 Message Date
Gustavo Henrique Santos Souza de Miranda 0e6ac619ff Added Turbo Vision License and changed the version on the about abox 2025-06-24 20:44:01 -03:00
Gustavo Henrique Santos Souza de Miranda 410e11c6e9 Added a custom about box 2025-06-24 20:33:03 -03:00
Gustavo Henrique Santos Souza de Miranda d80d32127d Started the project with a basic Turbo Vision Skeleton 2025-06-24 19:19:12 -03:00
9 changed files with 665 additions and 0 deletions

1
.gitignore vendored
View File

@ -0,0 +1 @@
.idea/

30
CMakeLists.txt Normal file
View File

@ -0,0 +1,30 @@
cmake_minimum_required(VERSION 3.31)
project(Pilgrim)
set(CMAKE_CXX_STANDARD 17)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
if(EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/lib/tvision/CMakeLists.txt")
add_subdirectory(lib/tvision)
else()
message(FATAL_ERROR "TVision submodule não encontrado em lib/tvision")
endif()
add_executable(Pilgrim src/main.cpp
src/PilgrimApp.cpp
src/PilgrimApp.h
src/MainWindow.cpp
src/MainWindow.h
src/AboutDialog.cpp
src/AboutDialog.h
)
target_link_libraries(${PROJECT_NAME} tvision)
if(UNIX)
target_link_libraries(${PROJECT_NAME} ncurses)
endif()
# Para debug
set(CMAKE_BUILD_TYPE Debug)
if(CMAKE_BUILD_TYPE STREQUAL "Release")
set(CMAKE_CXX_FLAGS_RELEASE "-O3 -DNDEBUG")
endif()

235
src/AboutDialog.cpp Normal file
View File

@ -0,0 +1,235 @@
// Componentes necessários para a declaração em AboutDialog.h
#define Uses_TDialog
// Componentes necessários para a implementação em AboutDialog.cpp
#define Uses_TStaticText
#define Uses_TButton
#define Uses_TScrollBar
#define Uses_TEditor
#define Uses_TRect
#define Uses_TView
#define Uses_TWindowInit // TDialog herda dele, então é bom ter.
#define Uses_TEvent
#define Uses_TKeys
#define Uses_TScreen
// 2. AGORA INCLUA SEU CABEÇALHO.
// Ele irá puxar <tvision/tv.h> com todas as definições acima ativadas.
#include "AboutDialog.h"
// Outras inclusões C++ padrão
#include <cstring> // Para strlen
#include <fstream> // Para leitura de arquivo
#include <sstream> // Para stringstream
#include <iostream> // Para cerr
// Função para fazer wrap do texto
std::string wrapText(const std::string& text, int maxWidth) {
std::string result;
std::istringstream iss(text);
std::string line;
while (std::getline(iss, line)) {
if (line.length() <= maxWidth) {
result += line + "\n";
} else {
// Fazer wrap da linha
std::string currentLine;
std::istringstream wordStream(line);
std::string word;
while (wordStream >> word) {
if (currentLine.length() + word.length() + 1 <= maxWidth) {
if (!currentLine.empty()) currentLine += " ";
currentLine += word;
} else {
if (!currentLine.empty()) {
result += currentLine + "\n";
currentLine = word;
} else {
// Palavra muito longa, quebrar
result += word.substr(0, maxWidth) + "\n";
currentLine = word.substr(maxWidth);
}
}
}
if (!currentLine.empty()) {
result += currentLine + "\n";
}
}
}
return result;
}
TAboutDialog::TAboutDialog() :
TWindowInit(&TAboutDialog::initFrame),
TDialog(TRect(0, 0, 100, 30), "About Pilgrim")
{
// Centralizar o diálogo programaticamente
int x = (TScreen::screenWidth - 100) / 2;
int y = (TScreen::screenHeight - 30) / 2;
moveTo(x, y);
insert(new TStaticText(TRect(40, 1, 60, 2), "P I L G R I M"));
insert(new TStaticText(TRect(35, 2, 65, 3), "Digital Travel Journal"));
insert(new TStaticText(TRect(41, 3, 59, 4), "Version 0.0.1 - 2025"));
insert(new TStaticText(TRect(2, 4, 98, 5),
"══════════════════════════════════════════════════════════════════════════════════════════════"));
const char* developerInfo =
"Developed by: Gustavo H. S. S. M.\n"
"GitHub: https://github.com/gmbrax\n"
"Git: https://git.gustavomiranda.xyz";
insert(new TStaticText(TRect(3, 6, 97, 10), developerInfo));
insert(new TStaticText(TRect(3, 11, 20, 12), "License:"));
// Criar apenas scrollbar vertical
TScrollBar* vScrollBar = new TScrollBar(TRect(96, 12, 97, 23));
insert(vScrollBar);
// Criar TEditor para mostrar a licença com scroll vertical apenas - área maior
TEditor* editor = new TEditor(TRect(3, 12, 96, 23), nullptr, vScrollBar, nullptr, 10000);
// Tentar ler o arquivo LICENSE
std::string licenseContent;
std::ifstream licenseFile;
// Tentar diferentes caminhos possíveis para o arquivo LICENSE
const char* possiblePaths[] = {
"LICENSE",
"../LICENSE",
"../../LICENSE",
"./LICENSE"
};
bool fileFound = false;
for (const char* path : possiblePaths) {
licenseFile.open(path);
if (licenseFile.is_open()) {
std::stringstream buffer;
buffer << licenseFile.rdbuf();
licenseContent = buffer.str();
licenseFile.close();
fileFound = true;
break;
}
}
if (!fileFound) {
// Fallback se não conseguir ler o arquivo
licenseContent = "Error loading LICENSE file.\n\n"
"Copyright (c) 2025 GHMiranda.\n\n"
"This software is distributed under the BSD license terms.\n\n"
"Redistribution and use in source and binary forms, with or without\n"
"modification, are permitted provided that the following conditions\n"
"are met:\n\n"
"1. Redistributions of source code must retain the above copyright\n"
" notice, this list of conditions and the following disclaimer.\n\n"
"2. Redistributions in binary form must reproduce the above copyright\n"
" notice, this list of conditions and the following disclaimer in\n"
" the documentation and/or other materials provided with the\n"
" distribution.\n\n"
"3. Neither the name of the copyright holder nor the names of its\n"
" contributors may be used to endorse or promote products derived\n"
" from this software without specific prior written permission.\n\n"
"THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS\n"
"\"AS IS\" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT\n"
"LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS\n"
"FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE\n"
"COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,\n"
"INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,\n"
"BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;\n"
"LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER\n"
"CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n"
"LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN\n"
"ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE\n"
"POSSIBILITY OF SUCH DAMAGE.";
}
// Adicionar informações sobre bibliotecas utilizadas
licenseContent += "\n\n────────────────────────────────────────────────────────────────────────────\n\n";
licenseContent += "USED LIBRARIES:\n\n";
licenseContent += "• Turbo Vision (Magiblot fork)\n";
licenseContent += " Modern port of Borland's Turbo Vision library\n";
licenseContent += " GitHub: https://github.com/magiblot/tvision\n\n";
licenseContent += "BORLAND INTERNATIONAL DISCLAIMER:\n\n";
licenseContent += "Borland International made the Turbo Vision source code public, accompanied\n";
licenseContent += "by the following disclaimer:\n\n";
licenseContent += "DISCLAIMER AND LIMITATION OF LIABILITY: Borland does not make\n";
licenseContent += "or give any representation or warranty with respect to the\n";
licenseContent += "usefulness or the efficiency of this software, it being\n";
licenseContent += "understood that the degree of success with which equipment,\n";
licenseContent += "software, modifications, and other materials can be applied to\n";
licenseContent += "data processing is dependent upon many factors, many of which\n";
licenseContent += "are not under Borland's control. ACCORDINGLY, THIS SOFTWARE IS\n";
licenseContent += "PROVIDED 'AS IS' WITHOUT EXPRESS OR IMPLIED WARRANTIES,\n";
licenseContent += "INCLUDING NO WARRANTIES OF MERCHANTABILITY, FITNESS FOR A\n";
licenseContent += "PARTICULAR PURPOSE, OR NONINFRINGEMENT. THIS SOFTWARE IS\n";
licenseContent += "PROVIDED GRATUITOUSLY AND, ACCORDINGLY, BORLAND SHALL NOT BE\n";
licenseContent += "LIABLE UNDER ANY THEORY FOR ANY DAMAGES SUFFERED BY YOU OR ANY\n";
licenseContent += "USER OF THE SOFTWARE. BORLAND WILL NOT SUPPORT THIS SOFTWARE\n";
licenseContent += "AND IS UNDER NO OBLIGATION TO ISSUE UPDATES TO THIS SOFTWARE.\n\n";
licenseContent += "WITHOUT LIMITING THE GENERALITY OF THE FOREGOING, NEITHER\n";
licenseContent += "BORLAND NOR ITS SUPPLIERS SHALL BE LIABLE FOR (a) INCIDENTAL,\n";
licenseContent += "CONSEQUENTIAL, SPECIAL OR INDIRECT DAMAGES OF ANY SORT, WHETHER\n";
licenseContent += "ARISING IN TORT, CONTRACT OR OTHERWISE, EVEN IF BORLAND HAS BEEN\n";
licenseContent += "INFORMED OF THE POSSIBILITY OF SUCH DAMAGES, OR (b) FOR ANY\n";
licenseContent += "CLAIM BY ANY OTHER PARTY. SOME STATES DO NOT ALLOW THE\n";
licenseContent += "EXCLUSION OR LIMITATION OF INCIDENTAL OR CONSEQUENTIAL DAMAGES,\n";
licenseContent += "SO THIS LIMITATION AND EXCLUSION MAY NOT APPLY TO YOU.\n\n";
licenseContent += "MAGIBLOT MIT LICENSE:\n\n";
licenseContent += "The copyright below applies to the modifications made by magiblot and other\n";
licenseContent += "contributors to the original source code and to the source code that has been\n";
licenseContent += "written from scratch.\n\n";
licenseContent += "MIT License\n\n";
licenseContent += "Copyright 2019-2025 magiblot <magiblot@hotmail.com>\n\n";
licenseContent += "Permission is hereby granted, free of charge, to any person obtaining a copy\n";
licenseContent += "of this software and associated documentation files (the \"Software\"), to deal\n";
licenseContent += "in the Software without restriction, including without limitation the rights\n";
licenseContent += "to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n";
licenseContent += "copies of the Software, and to permit persons to whom the Software is\n";
licenseContent += "furnished to do so, subject to the following conditions:\n\n";
licenseContent += "The above copyright notice and this permission notice shall be included in\n";
licenseContent += "all copies or substantial portions of the Software.\n\n";
licenseContent += "THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n";
licenseContent += "IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n";
licenseContent += "FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n";
licenseContent += "AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n";
licenseContent += "LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n";
licenseContent += "OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\n";
licenseContent += "SOFTWARE.";
// Fazer wrap do texto para caber na largura do editor (93 caracteres)
std::string wrappedText = wrapText(licenseContent, 93);
editor->insertText(wrappedText.c_str(), wrappedText.length(), true);
editor->setState(sfCursorVis, false); // Desabilitar cursor
editor->setState(sfActive, false); // Desabilitar edição
insert(editor);
insert(new TButton(TRect(45, 27, 55, 29), "~O~K", cmOK, bfDefault));
}
void TAboutDialog::handleEvent(TEvent& event) {
TDialog::handleEvent(event);
if (event.what == evKeyDown) {
switch (event.keyDown.keyCode) {
case kbAltX:
case kbEsc:
close();
clearEvent(event);
break;
}
}
if (event.what == evCommand) {
switch (event.message.command) {
case cmOK:
close();
clearEvent(event);
break;
}
}
}

28
src/AboutDialog.h Normal file
View File

@ -0,0 +1,28 @@
#ifndef ABOUTDIALOG_H
#define ABOUTDIALOG_H
// Passo 1: Defina TODOS os componentes da TVision necessários para esta janela aqui.
#define Uses_TDialog
#define Uses_TStaticText
#define Uses_TButton
#define Uses_TScrollBar
#define Uses_TEditor
#define Uses_TRect
#define Uses_TView
#define Uses_TWindowInit
#define Uses_TEvent
#define Uses_TKeys
#define Uses_TScreen
// Passo 2: Agora, inclua os cabeçalhos necessários.
#include <tvision/tv.h>
// Passo 3: Defina a sua classe.
class TAboutDialog : public TDialog
{
public:
TAboutDialog();
void handleEvent(TEvent& event) override;
};
#endif // ABOUTDIALOG_H

103
src/MainWindow.cpp Normal file
View File

@ -0,0 +1,103 @@
#include "MainWindow.h"
#include <string.h>
#include <stdio.h>
MainWindow::MainWindow(TRect bounds, const char* title, int windowNo)
: TWindow(bounds, title, windowNo),
TWindowInit(&TWindow::initFrame),
listBox(nullptr),
scrollBar(nullptr),
strings(nullptr),
windowNumber(windowNo) {
options |= ofTileable;
setupInterior();
}
MainWindow::~MainWindow() {
if (strings) {
destroy(strings);
strings = nullptr;
}
}
void MainWindow::close() {
destroy(this);
}
void MainWindow::setupInterior() {
// Criar a coleção de strings
strings = new TStringCollection(20, 5);
// Adicionar itens usando newStr para gerenciamento automático de memória
strings->insert(newStr("Arquivo de configuração"));
strings->insert(newStr("Dados do usuário"));
strings->insert(newStr("Log de sistema"));
strings->insert(newStr("Backup automático"));
strings->insert(newStr("Cache temporário"));
strings->insert(newStr("Documentos recentes"));
strings->insert(newStr("Preferências"));
strings->insert(newStr("Histórico de comandos"));
strings->insert(newStr("Plugins instalados"));
strings->insert(newStr("Templates disponíveis"));
strings->insert(newStr("Macros personalizadas"));
strings->insert(newStr("Filtros ativos"));
strings->insert(newStr("Conexões de rede"));
strings->insert(newStr("Drivers de dispositivo"));
strings->insert(newStr("Atualizações pendentes"));
// Obter as dimensões internas da janela
TRect interiorBounds = getExtent();
interiorBounds.grow(-1, -1);
// Criar scrollbar vertical
TRect scrollBarBounds = interiorBounds;
scrollBarBounds.a.x = scrollBarBounds.b.x - 1;
scrollBar = new TScrollBar(scrollBarBounds);
insert(scrollBar);
// Criar listbox
TRect listBoxBounds = interiorBounds;
listBoxBounds.b.x = scrollBarBounds.a.x;
listBox = new TListBox(listBoxBounds, 1, scrollBar);
listBox->newList(strings);
insert(listBox);
// Focar no listbox
listBox->select();
}
void MainWindow::handleEvent(TEvent& event) {
TWindow::handleEvent(event);
if (event.what == evKeyDown) {
switch (event.keyDown.keyCode) {
case kbEnter:
if (listBox && listBox->focused >= 0) {
char* selectedItem = (char*)strings->at(listBox->focused);
if (selectedItem) {
char message[256];
sprintf(message, "Item selecionado: %s\n\nJanela: %d",
selectedItem, windowNumber);
messageBox(message, mfInformation | mfOKButton);
}
}
clearEvent(event);
break;
case kbEsc:
close();
clearEvent(event);
break;
}
}
if (event.what == evCommand) {
switch (event.message.command) {
case cmClose:
close();
clearEvent(event);
break;
}
}
}

57
src/MainWindow.h Normal file
View File

@ -0,0 +1,57 @@
#ifndef MAINWINDOW_H
#define MAINWINDOW_H
#define Uses_TKeys
#define Uses_TApplication
#define Uses_TEvent
#define Uses_TRect
#define Uses_TDialog
#define Uses_TStaticText
#define Uses_TButton
#define Uses_TMenuBar
#define Uses_TSubMenu
#define Uses_TMenuItem
#define Uses_TStatusLine
#define Uses_TStatusItem
#define Uses_TStatusDef
#define Uses_TDeskTop
#define Uses_TView
#define Uses_TWindow
#define Uses_TFrame
#define Uses_TScrollBar
#define Uses_TListBox
#define Uses_TCollection
#define Uses_TStringCollection
#define Uses_MsgBox
#define Uses_TProgram
#define Uses_TMenu
#define Uses_TWindowInit
#include <tvision/tv.h>
const int cmNewWindow = 100;
const int cmOpenFile = 101;
const int cmCalculator = 104;
const int cmCalendar = 105;
const int cmAsciiTable = 107;
const int cmAbout = 109;
class MainWindow : public TWindow {
public:
MainWindow(TRect bounds, const char* title, int windowNo);
~MainWindow();
void handleEvent(TEvent& event) override;
void close() override;
private:
void setupInterior();
TListBox* listBox;
TScrollBar* scrollBar;
TStringCollection* strings;
int windowNumber;
};
#endif // MAINWINDOW_H

133
src/PilgrimApp.cpp Normal file
View File

@ -0,0 +1,133 @@
#include "PilgrimApp.h"
#include "AboutDialog.h"
#include <stdio.h>
#include <stdlib.h>
#include <iostream>
PilgrimApp::PilgrimApp() :
TProgInit(&PilgrimApp::initStatusLine,
&PilgrimApp::initMenuBar,
&PilgrimApp::initDeskTop),
TApplication(),
windowCount(0) {
}
TMenuBar* PilgrimApp::initMenuBar(TRect bounds) {
bounds.b.y = bounds.a.y + 1;
return new TMenuBar(bounds,
*new TSubMenu("~≡~", 0, hcNoContext) +
*new TMenuItem("~A~bout...", cmAbout, kbNoKey, hcNoContext, "F1") +
newLine() +
*new TMenuItem("~N~ew", cmNewWindow, kbF4, hcNoContext, "F4") +
*new TMenuItem("~O~pen...", cmOpenFile, kbF3, hcNoContext, "F3") +
newLine() +
*new TMenuItem("~D~OS Shell", cmDosShell, kbNoKey, hcNoContext) +
newLine() +
*new TMenuItem("E~x~it", cmQuit, kbAltX, hcNoContext, "Alt+X") +
*new TSubMenu("~W~indow", 0, hcNoContext) +
*new TMenuItem("~T~ile", cmTile, kbF5, hcNoContext, "F5") +
*new TMenuItem("C~a~scade", cmCascade, kbF4, hcNoContext, "Shift+F5")
);
}
TStatusLine* PilgrimApp::initStatusLine(TRect bounds) {
bounds.a.y = bounds.b.y - 1;
return new TStatusLine(bounds,
*new TStatusDef(0, 0xFFFF) +
*new TStatusItem("~F1~ Ajuda", kbF1, cmAbout) +
*new TStatusItem("~F3~ Abrir", kbF3, cmOpenFile) +
*new TStatusItem("~F4~ Nova", kbF4, cmNewWindow) +
*new TStatusItem("~F5~ Organizar", kbF5, cmTile) +
*new TStatusItem("~Alt+X~ Sair", kbAltX, cmQuit)
);
}
void PilgrimApp::handleEvent(TEvent& event) {
TApplication::handleEvent(event);
if (event.what == evCommand) {
switch (event.message.command) {
case cmNewWindow:
newWindow();
clearEvent(event);
break;
case cmOpenFile:
openFile();
clearEvent(event);
break;
case cmTile:
tile();
clearEvent(event);
break;
case cmCascade:
cascade();
clearEvent(event);
break;
case cmAbout:
about();
clearEvent(event);
break;
case cmDosShell:
dosShell();
clearEvent(event);
break;
default:
return;
}
}
}
void PilgrimApp::idle() {
TApplication::idle();
// Aqui você pode adicionar processamento em background
}
void PilgrimApp::newWindow() {
windowCount++;
char windowTitle[50];
sprintf(windowTitle, "Pilgrim - Janela %d", windowCount);
TRect bounds = deskTop->getExtent();
bounds.grow(-1, -1);
bounds.move(windowCount % 5, (windowCount % 5) + 1);
bounds.b.x = bounds.a.x + 50;
bounds.b.y = bounds.a.y + 18;
MainWindow* window = new MainWindow(bounds, windowTitle, windowCount);
deskTop->insert(window);
}
void PilgrimApp::openFile() {
messageBox("Funcionalidade 'Abrir Arquivo' ainda não implementada.\n\n"
"Esta será uma funcionalidade futura do Pilgrim.",
mfInformation | mfOKButton);
}
void PilgrimApp::tile() {
deskTop->tile(deskTop->getExtent());
}
void PilgrimApp::cascade() {
deskTop->cascade(deskTop->getExtent());
}
void PilgrimApp::about() {
TAboutDialog* dialog = new TAboutDialog();
deskTop->insert(dialog);
}
void PilgrimApp::dosShell() {
suspend();
std::cout << "Digite 'exit' para retornar ao Pilgrim." << std::endl;
system(getenv("COMSPEC") ? getenv("COMSPEC") : "/bin/sh");
resume();
redraw();
}

49
src/PilgrimApp.h Normal file
View File

@ -0,0 +1,49 @@
#ifndef PILGRIMAPP_H
#define PILGRIMAPP_H
#define Uses_TKeys
#define Uses_TApplication
#define Uses_TEvent
#define Uses_TRect
#define Uses_TDialog
#define Uses_TStaticText
#define Uses_TButton
#define Uses_TMenuBar
#define Uses_TSubMenu
#define Uses_TMenuItem
#define Uses_TStatusLine
#define Uses_TStatusItem
#define Uses_TStatusDef
#define Uses_TDeskTop
#define Uses_TView
#define Uses_TWindow
#define Uses_TFrame
#define Uses_MsgBox
#define Uses_TMenu
#define Uses_TProgram
#include <tvision/tv.h>
#include "MainWindow.h"
class PilgrimApp : public TApplication {
public:
PilgrimApp();
static TMenuBar* initMenuBar(TRect bounds);
static TStatusLine* initStatusLine(TRect bounds);
void handleEvent(TEvent& event) override;
void idle() override;
private:
void newWindow();
void openFile();
void tile();
void cascade();
void about();
void dosShell();
int windowCount;
};
#endif // PILGRIMAPP_H

29
src/main.cpp Normal file
View File

@ -0,0 +1,29 @@
#define Uses_TKeys
#define Uses_TApplication
#define Uses_TEvent
#define Uses_TRect
#define Uses_TDialog
#define Uses_TStaticText
#define Uses_TButton
#define Uses_TMenuBar
#define Uses_TSubMenu
#define Uses_TMenuItem
#define Uses_TStatusLine
#define Uses_TStatusItem
#define Uses_TStatusDef
#define Uses_TDeskTop
#define Uses_TView
#define Uses_TWindow
#define Uses_TFrame
#define Uses_MsgBox
#define Uses_TMenu
#define Uses_TProgram
#include <tvision/tv.h>
#include "PilgrimApp.h"
int main() {
PilgrimApp app;
app.run();
return 0;
}