diff --git a/Makefile b/Makefile
index 8951fbc..9538339 100644
--- a/Makefile
+++ b/Makefile
@@ -1,4 +1,4 @@
-.PHONY: build tests install
+.PHONY: build tests install i18n
build:
meson setup build
@@ -13,3 +13,7 @@ install: tests
check:
cppcheck --language=c++ --enable=all -q src \
--suppress=missingInclude
+
+i18n:
+ lupdate src -ts i18n/pix_en.ts
+ lupdate src -ts i18n/pix_fr.ts
diff --git a/i18n/pix_en.ts b/i18n/pix_en.ts
index f1c0645..25d7ea1 100644
--- a/i18n/pix_en.ts
+++ b/i18n/pix_en.ts
@@ -4,17 +4,56 @@
QAction
-
+
+
+ New Project
+
+
+
+
+ Close Project
+
+
+
Quit
+
+ QDialog
+
+
+
+ New Project
+
+
+
+ QLineEdit
+
+
+
+ New project name
+
+
QMenu
-
+
File
+
+ QPushButton
+
+
+
+ New Project
+
+
+
+
+ Cancel
+
+
diff --git a/i18n/pix_fr.ts b/i18n/pix_fr.ts
index 78ce21c..c7d7719 100644
--- a/i18n/pix_fr.ts
+++ b/i18n/pix_fr.ts
@@ -4,17 +4,56 @@
QAction
-
+
+
+ Nouveau Projet
+
+
+
+
+ Fermer Projet
+
+
+
Quitter
+
+ QDialog
+
+
+
+ Nouveau Projet
+
+
+
+ QLineEdit
+
+
+
+ Nom du nouveau projet
+
+
QMenu
-
+
Fichier
+
+ QPushButton
+
+
+
+ Nouveau Projet
+
+
+
+
+ Annuler
+
+
diff --git a/meson.build b/meson.build
index 5e7668e..175e063 100644
--- a/meson.build
+++ b/meson.build
@@ -1,7 +1,7 @@
project(
'pixtool',
'cpp',
- version: '0.0.0',
+ version: '0.0',
default_options: [
'cpp_std=c++17',
'warning_level=3'
@@ -45,6 +45,7 @@ pixtool = static_library(
# model
'src/model/PixTool.cpp',
+ 'src/model/Project.cpp',
'src/model/Command.cpp',
'src/model/Shortcut.cpp',
'src/model/CommandRunner.cpp',
diff --git a/src/Presenter.cpp b/src/Presenter.cpp
index 16e4d8f..92c744e 100644
--- a/src/Presenter.cpp
+++ b/src/Presenter.cpp
@@ -1,5 +1,6 @@
#include "Presenter.hpp"
#include "src/model/Event.hpp"
+#include "model/Observable.hpp"
namespace pt
{
@@ -13,7 +14,42 @@ namespace pt
{
}
- void Presenter::update(model::Event& event) /*override*/
+ void Presenter::update(model::Observable& source, model::Event& event) /*override*/
+ {
+ if (&source == &m_pixtool)
+ {
+ update_pixtool(event);
+ }
+ else if (&source == &m_window)
+ {
+ update_window(event);
+ }
+ }
+
+ void Presenter::update_pixtool(model::Event const& event)
+ {
+ if (event.type == model::EVENT_NEW_PROJECT)
+ {
+ m_window.show_project(event.project.name, event.project.dir);
+ }
+
+ if (event.type == model::EVENT_QUERY_NEW_PROJECT)
+ {
+ m_window.on_new_project();
+ }
+
+ if (event.type == model::EVENT_CLOSE_PROJECT)
+ {
+ m_window.hide_project();
+ }
+
+ if (event.type == model::EVENT_QUERY_CLOSE_PROJECT)
+ {
+ m_window.on_close_project();
+ }
+ }
+
+ void Presenter::update_window(model::Event const& event)
{
if (event.type == model::EVENT_KEYPRESSED)
{
@@ -24,5 +60,15 @@ namespace pt
{
m_pixtool.quit();
}
+
+ if (event.type == model::EVENT_NEW_PROJECT)
+ {
+ m_pixtool.new_project(event.project.name, event.project.dir);
+ }
+
+ if (event.type == model::EVENT_CLOSE_PROJECT)
+ {
+ m_pixtool.close_project();
+ }
}
}
diff --git a/src/Presenter.hpp b/src/Presenter.hpp
index 0847422..f050e29 100644
--- a/src/Presenter.hpp
+++ b/src/Presenter.hpp
@@ -15,7 +15,10 @@ namespace pt
explicit Presenter(gui::Window& window, model::PixTool& pixtool);
virtual ~Presenter();
- void update(model::Event& event) override;
+ void update(model::Observable& source, model::Event& event) override;
+ void update_pixtool(model::Event const& event);
+ void update_window(model::Event const& event);
+
private:
gui::Window& m_window;
model::PixTool& m_pixtool;
diff --git a/src/gui/Window.cpp b/src/gui/Window.cpp
index 0f3c5c8..6e669a9 100644
--- a/src/gui/Window.cpp
+++ b/src/gui/Window.cpp
@@ -1,11 +1,21 @@
-#include
#include "../model/Shortcut.hpp"
+#include "qboxlayout.h"
+#include "src/model/Event.hpp"
#include "Window.hpp"
#include "conf.hpp"
+
#include "qmainwindow.h"
#include "qnamespace.h"
-#include "src/model/Event.hpp"
+#include "qtabwidget.h"
+
+#include
#include
+#include
+#include
+#include
+#include
+#include
+#include
namespace pt
{
@@ -14,14 +24,34 @@ namespace pt
/*explicit*/ Window::Window(QWidget* parent)
: QMainWindow(parent)
{
- setWindowTitle(QString::fromStdString("PixTool v" + PT_VERSION));
+ setWindowTitle(QString::fromStdString(m_base_title));
setMinimumSize(QSize {640, 480});
- QMenuBar* bar = new QMenuBar {this};
+ // Window layout
+ // =============
+ QWidget* central = new QWidget {};
+
+ setCentralWidget(central);
+
+ QVBoxLayout* vbox = new QVBoxLayout {central};
+
+ // Menu
+ // ====
+ QMenuBar* bar = new QMenuBar {};
+ vbox->addWidget(bar);
QMenu* file = new QMenu {QMenu::tr("file")};
bar->addMenu(file);
+ QAction* new_project = new QAction {QAction::tr("new-project")};
+ file->addAction(new_project);
+ connect(new_project, &QAction::triggered, this, &Window::on_new_project);
+
+ m_close_project = new QAction {QAction::tr("close-project")};
+ file->addAction(m_close_project);
+ connect(m_close_project, &QAction::triggered, this, &Window::on_close_project);
+ m_close_project->setEnabled(false);
+
QAction* quit = new QAction {QAction::tr("quit")};
file->addAction(quit);
@@ -68,5 +98,81 @@ namespace pt
notify(e);
}
}
+
+ void Window::show_project(std::string const& name,
+ std::filesystem::path const& dir)
+ {
+ setWindowTitle(QString::fromStdString(m_base_title + " [" + name
+ + "]: " + dir.string()));
+ m_close_project->setEnabled(true);
+ }
+
+ void Window::hide_project()
+ {
+ setWindowTitle(QString::fromStdString(m_base_title));
+ m_close_project->setEnabled(false);
+ }
+
+ void Window::on_new_project()
+ {
+ QDialog* dialog = new QDialog {this};
+ dialog->setWindowTitle(QDialog::tr("new-project"));
+
+ auto* layout = new QVBoxLayout {dialog};
+
+ QLineEdit* name_field = new QLineEdit {dialog};
+ name_field->setPlaceholderText(QLineEdit::tr("new-project-name"));
+ layout->addWidget(name_field);
+
+ std::filesystem::path project_dir = std::filesystem::current_path();
+
+ {
+ auto* path_btn = new QPushButton {QString::fromStdString(project_dir.string())};
+
+ connect(path_btn, &QPushButton::pressed, [&](){
+ auto* file_diag = new QFileDialog {};
+ file_diag->setFileMode(QFileDialog::Directory);
+ file_diag->setOption(QFileDialog::ShowDirsOnly);
+ file_diag->setAcceptMode(QFileDialog::AcceptOpen);
+ file_diag->setViewMode(QFileDialog::ViewMode::List);
+
+ if (file_diag->exec())
+ {
+ auto dir = file_diag->directory();
+ project_dir = dir.absolutePath().toStdString();
+ path_btn->setText(QString::fromStdString(project_dir.string()));
+ }
+ });
+
+ layout->addWidget(path_btn);
+ }
+
+ {
+ auto* btn_layout = new QHBoxLayout {};
+ layout->addLayout(btn_layout);
+
+ auto ok_btn = new QPushButton {QPushButton::tr("new-project"), dialog};
+ btn_layout->addWidget(ok_btn);
+ connect(ok_btn, &QPushButton::pressed, [dialog](){ dialog->done(true); });
+
+ auto cancel_btn = new QPushButton {QPushButton::tr("cancel-new-project"), dialog};
+ btn_layout->addWidget(cancel_btn);
+ connect(cancel_btn, &QPushButton::pressed, [dialog](){ dialog->done(false); });
+
+ if (dialog->exec())
+ {
+ std::string project_name = name_field->text().toStdString();
+ model::Event e {model::EVENT_NEW_PROJECT};
+ e.project.name = project_name;
+ e.project.dir = project_dir;
+ notify(e);
+ }
+ }
+ }
+
+ void Window::on_close_project()
+ {
+ notify(model::EVENT_CLOSE_PROJECT);
+ }
}
}
diff --git a/src/gui/Window.hpp b/src/gui/Window.hpp
index 264efd3..87ceaa6 100644
--- a/src/gui/Window.hpp
+++ b/src/gui/Window.hpp
@@ -17,9 +17,23 @@ namespace pt
explicit Window(QWidget* parent=nullptr);
virtual ~Window();
+ // Events
+ // ======
void keyPressEvent(QKeyEvent* event) override;
+ // Project
+ // =======
+ void show_project(std::string const& name,
+ std::filesystem::path const& dir);
+ void hide_project();
+
+ void on_new_project();
+ void on_close_project();
+
private:
+ std::string const m_base_title = "PIXTOOL " + PT_VERSION;
+ QAction* m_close_project;
+
};
}
}
diff --git a/src/main.cpp b/src/main.cpp
index 7bef5a2..728a689 100644
--- a/src/main.cpp
+++ b/src/main.cpp
@@ -23,6 +23,7 @@ int main(int argc, char** argv)
pt::model::PixTool pixtool;
auto presenter = std::make_shared(window, pixtool);
+ pixtool.add_observer(presenter);
window.add_observer(presenter);
pixtool.ready();
diff --git a/src/model/Event.hpp b/src/model/Event.hpp
index 9480cbd..b99633b 100644
--- a/src/model/Event.hpp
+++ b/src/model/Event.hpp
@@ -4,8 +4,10 @@
#include "../commons.hpp"
#include "Shortcut.hpp"
-#define EVENT_TYPE(G) \
- G(EVENT_KEYPRESSED), \
+#define EVENT_TYPE(G) \
+ G(EVENT_NEW_PROJECT), G(EVENT_CLOSE_PROJECT), \
+ G(EVENT_QUERY_NEW_PROJECT), G(EVENT_QUERY_CLOSE_PROJECT), \
+ G(EVENT_KEYPRESSED), \
G(EVENT_QUIT)
namespace pt
@@ -19,12 +21,19 @@ namespace pt
KeyMod keymod {""};
};
+ struct EventProject
+ {
+ std::string name;
+ std::filesystem::path dir;
+ };
+
struct Event
{
explicit Event(EventType ty) : type { ty } {}
EventType type;
EventKeyPressed key_pressed;
+ EventProject project;
};
}
}
diff --git a/src/model/Observable.cpp b/src/model/Observable.cpp
index 1553cc9..7474f79 100644
--- a/src/model/Observable.cpp
+++ b/src/model/Observable.cpp
@@ -23,9 +23,15 @@ namespace pt
{
if (auto ob = observer.lock(); ob)
{
- ob->update(event);
+ ob->update(*this, event);
}
}
}
+
+ void Observable::notify(EventType type)
+ {
+ Event e { type };
+ notify(e);
+ }
}
}
diff --git a/src/model/Observable.hpp b/src/model/Observable.hpp
index 73fe487..c9f8ef1 100644
--- a/src/model/Observable.hpp
+++ b/src/model/Observable.hpp
@@ -18,6 +18,7 @@ namespace pt
void add_observer(std::shared_ptr observer);
void notify(Event& event);
+ void notify(EventType type);
private:
std::vector> m_observers;
diff --git a/src/model/Observer.hpp b/src/model/Observer.hpp
index a219eea..900cdd1 100644
--- a/src/model/Observer.hpp
+++ b/src/model/Observer.hpp
@@ -8,13 +8,15 @@ namespace pt
{
namespace model
{
+ class Observable;
+
class Observer
{
public:
explicit Observer();
virtual ~Observer();
- virtual void update(Event& event) = 0;
+ virtual void update(Observable& source, Event& event) = 0;
private:
};
}
diff --git a/src/model/PixTool.cpp b/src/model/PixTool.cpp
index a6fb139..5629ef9 100644
--- a/src/model/PixTool.cpp
+++ b/src/model/PixTool.cpp
@@ -2,6 +2,8 @@
#include "PixTool.hpp"
#include "CommandRunner.hpp"
#include "cmds/Quit.hpp"
+#include "cmds/Project.hpp"
+#include "src/model/Event.hpp"
namespace pt
{
@@ -13,6 +15,12 @@ namespace pt
m_cmd_runner->bind(Shortcut {{KeyMod {"X", {PT_CONTROL}},
KeyMod {"C", {PT_CONTROL}}}},
std::make_shared());
+
+ m_cmd_runner->bind(Shortcut {{KeyMod {"N", {PT_CONTROL}}}},
+ std::make_shared());
+
+ m_cmd_runner->bind(Shortcut {{KeyMod {"W", {PT_CONTROL}}}},
+ std::make_shared());
}
/*virtual*/ PixTool::~PixTool()
@@ -34,5 +42,29 @@ namespace pt
spdlog::info("done");
exit(0);
}
+
+ void PixTool::new_project(std::string const& name,
+ std::filesystem::path const& dir)
+ {
+ m_project = std::make_unique(name, dir);
+
+ Event e {EVENT_NEW_PROJECT};
+ e.project.name = name;
+ e.project.dir = dir;
+ notify(e);
+
+ spdlog::info("new project '" + name + "'");
+ }
+
+ void PixTool::close_project()
+ {
+ if (m_project)
+ {
+ std::string name = m_project->name();
+ m_project.reset();
+ notify(EVENT_CLOSE_PROJECT);
+ spdlog::info("close project '" + name + "'");
+ }
+ }
}
}
diff --git a/src/model/PixTool.hpp b/src/model/PixTool.hpp
index 9e7c98c..e15a3e7 100644
--- a/src/model/PixTool.hpp
+++ b/src/model/PixTool.hpp
@@ -3,6 +3,8 @@
#include "../commons.hpp"
#include "Shortcut.hpp"
+#include "Project.hpp"
+#include "Observable.hpp"
namespace pt
{
@@ -10,7 +12,7 @@ namespace pt
{
class CommandRunner;
- class PixTool
+ class PixTool: public Observable
{
public:
explicit PixTool();
@@ -20,8 +22,15 @@ namespace pt
void update(KeyMod const& km);
void quit();
+ // Project
+ // =======
+ void new_project(std::string const& name, std::filesystem::path const& dir);
+ bool has_project() const { return m_project != nullptr; }
+ void close_project();
+
private:
std::unique_ptr m_cmd_runner;
+ std::unique_ptr m_project;
};
}
}
diff --git a/src/model/Project.cpp b/src/model/Project.cpp
new file mode 100644
index 0000000..5430d32
--- /dev/null
+++ b/src/model/Project.cpp
@@ -0,0 +1,18 @@
+#include "Project.hpp"
+
+namespace pt
+{
+ namespace model
+ {
+ /*explicit*/ Project::Project(std::string const& name,
+ std::filesystem::path const& dir)
+ : m_name { name }
+ , m_dir { dir }
+ {
+ }
+
+ /*virtual*/ Project::~Project()
+ {
+ }
+ }
+}
diff --git a/src/model/Project.hpp b/src/model/Project.hpp
new file mode 100644
index 0000000..5d09c92
--- /dev/null
+++ b/src/model/Project.hpp
@@ -0,0 +1,27 @@
+#ifndef pt_model_PROJECT_HPP
+#define pt_model_PROJECT_HPP
+
+#include "../commons.hpp"
+
+namespace pt
+{
+ namespace model
+ {
+ class Project
+ {
+ public:
+ explicit Project(std::string const& name,
+ std::filesystem::path const& dir);
+ virtual ~Project();
+
+ inline std::string name() const { return m_name; }
+ inline std::filesystem::path dir() const { return m_dir; }
+
+ private:
+ std::string m_name;
+ std::filesystem::path m_dir;
+ };
+ }
+}
+
+#endif
diff --git a/src/model/cmds/Project.hpp b/src/model/cmds/Project.hpp
new file mode 100644
index 0000000..a2955f9
--- /dev/null
+++ b/src/model/cmds/Project.hpp
@@ -0,0 +1,40 @@
+#ifndef pt_cmds_PROJECT_HPP
+#define pt_cmds_PROJECT_HPP
+
+#include "../Command.hpp"
+#include "src/model/Event.hpp"
+
+namespace pt
+{
+ namespace cmds
+ {
+ struct QueryNewProject: public model::Command
+ {
+ std::string name;
+ std::filesystem::path dir;
+
+ explicit QueryNewProject()
+ : model::Command("query-new-project")
+ {}
+
+ void execute(model::PixTool& pixtool) override
+ {
+ pixtool.notify(model::EVENT_QUERY_NEW_PROJECT);
+ }
+ };
+
+ struct QueryCloseProject: public model::Command
+ {
+ explicit QueryCloseProject()
+ : model::Command("query-close-project") {}
+
+ void execute(model::PixTool& pixtool) override
+ {
+ pixtool.notify(model::EVENT_QUERY_CLOSE_PROJECT);
+ }
+ };
+
+ }
+}
+
+#endif