Skip to content

Commit

Permalink
Merge remote-tracking branch 'origin/dev' into dev-sge
Browse files Browse the repository at this point in the history
  • Loading branch information
sguionni committed Mar 29, 2024
2 parents 2f3dc54 + ed4c08b commit 979bf57
Show file tree
Hide file tree
Showing 11 changed files with 237 additions and 29 deletions.
169 changes: 168 additions & 1 deletion DOCUMENTATION.md
Original file line number Diff line number Diff line change
Expand Up @@ -321,6 +321,7 @@ SerializedObject va automatiquement ajouter le numéro de version de VTX dans le

```plantuml
@startuml
skinparam packageStyle rectangle
package Core
{
Expand Down Expand Up @@ -759,4 +760,170 @@ User -> User : Inifinite Happiness

VTXApp est la classe principal du module. Il contient un accès à la scene ainsi que

## UI
## UI

### Architecture

L'architecture de l'UI est divisée en 2 parties : Une partie abstraite qui pourrait être commune à l'ensemble des UIs, et une partie dédiée à une UI concrète (dans notre cas Qt).
Ainsi, la plupart des objets Qt héritent d'une classe abstraite dans UI::Core. Dans les faits, c'est relou à maintenir et ça n'a pas été bien maintenu tout le long du developpement. Je pense que la séparation n'est pas forcement la bonne et qu'il faudrait peut-être uniquement séparer le contenu "executif (les actions, la manipulation des données de VTXApp)" du contenu purement UI.

### Initialisation

Actuellement, VTX_UI est pensé pour générer plusieurs UI en fonction d'une directive de pre-proc (VTX_UI_STYLE défini temporairement dans "UI::UIGenerator.hpp"). L'idée est de pouvoir initialiser uniformément l'application peut importe l'UI choisie (CommandLine, Qt, autre).

Le schéma suivant récapitule les étapes d'initialisation
```plantuml
@startuml
actor User
participant main
participant include_tools.hpp
participant UIGenerator
participant AbstractUIApplication
participant ApplicationQT
participant Environment
participant VTXApp
participant MainWindow
participant LayoutReader
participant LayoutBuilder
participant ToolHandler
participant ToolRegistry
participant ExternalPlugin
User -> main : launch VTX
main -> include_tools.hpp : include
include_tools.hpp -> ExternalPlugin : include
ExternalPlugin -> ToolRegistry : registrate
main -> UIGenerator : createUI
UIGenerator -> ApplicationQT : instantiate
ApplicationQT -> main : return
main -> Environment : reference
main -> AbstractUIApplication : init
AbstractUIApplication -> ApplicationQT : init
main -> AbstractUIApplication : start (args)
AbstractUIApplication -> VTXApp : start(args)
AbstractUIApplication -> ApplicationQT : initUI
ApplicationQT -> MainWindow : create
AbstractUIApplication -> LayoutReader : read tool_config.json
LayoutReader -> AbstractUIApplication : return LayoutDescriptor from json
AbstractUIApplication -> LayoutBuilder : build UI layout with LayoutDescriptor
LayoutBuilder -> ToolHandler : createTool
ToolHandler -> ToolRegistry : createTool
ToolRegistry -> ExternalPlugin : instantiate
ToolRegistry -> ExternalPlugin : init
ExternalPlugin -> MainWindow : Add Panel / Buttons ...
ToolRegistry -> ToolHandler : return tool
ToolHandler -> ToolHandler : store tool
AbstractUIApplication -> ApplicationQT : startUI
ApplicationQT -> MainWindow : show
ApplicationQT -> ApplicationQT : UI loop
@enduml
```

### Mode

Dans l'UI, le mode est une configuration de VTX permettant un set de controllers et d'actions spécifique. Par défaut le mode de VTX est "Visualization" et est adapté à la visualization de molécule 3D. C'est l'unique mode implémenté pour le moment. Dans le futur, on pourrait imaginer un mode spécifique pour faire de l'illustration sur une image rendue, ou un mode spéciale pour l'édition de vidéos.

### Inputs

La réception des inputs utilisateurs (clavier + souris) est laissé à la discrétion de la bibliothèque d'UI utilisé. Un wrapper devra être fait pour envoyer les événements d'inputs à l'InputManager qui va ensuite les traiter et executer les callbacks correspondantes.
Les controllers ou n'importe quel autre objet peut ajouter sa propre callback pour réagir aux événements envoyés par l'InputManager.

De base dans Qt, chaque widget peut récupérer les événements d'inputs qui ne seront reçu que si le widget en question a le focus. Pour coller avec le système VTX, les inputs vont être capté depuis la MainWindow (qui a toujours le focus tant que l'appli à le focus) puis être transmis à l'InputManager.
Les widgets qui veulent récupérer l'input devront tester au besoin si ils ont bien le focus avant d'executer l'action correspondante.
Passer par un système centralisé permet de mieux gérer l'état du clavier lorsque l'application perd le focus par exemple.

Schéma d'un input executé via l'interface Qt
```plantuml
@startuml
actor User
participant ApplicationQt
participant QtEventManager
participant MainWindow
participant InputManager
participant AnyController
User -> ApplicationQt : launch VTX
ApplicationQt -> AnyController : Init
AnyController -> InputManager : add onKeyPressed callback
...
User -> QtEventManager : press Key F1
QtEventManager -> MainWindow : send KeyboardEvent
MainWindow -> InputManager : send KeyboardEvent
InputManager -> InputManager : treat KeyboardEvent
InputManager -> AnyController : onKeyPressed(F1)
AnyController -> AnyController : DoStuff
AnyController -> User : Something happened, user happy
@enduml
```

### Controllers

Les controllers sont des objets qui récupèrent les inputs de l'utilisateur afin d'effectuer des actions concrètes dans le logiciel. Dans VTX, on considère 3 types de controllers : Les CameraControllers qui permettent le contrôle de la camera, les PickerControllers qui gèrent le picking dans la scène et les ShortcutsControllers qui lient des actions à des séquences de touche (touche unique ou touche + modifier).

Selon le type de controller que l'on souhaite créer, il faut créer une classe héritant de Controller::BaseCameraController, Controller::BasePickerController ou Controller::BaseShortcutController. Si on souhaite créer un autre type de controller particulier, on peut hériter directement de BaseController.

Actuellement dans VTX, deux CameraController sont disponible (Trackball et Freefly), un PickerController (SelectionPicker) et trois ShortcutControllers (GlobalShortcut, VisualizationShortcut et DebugShortcut).

Diagramme de classe des Controllers
```plantuml
@startuml
skinparam packageStyle rectangle
package UI
{
package Core::Controller
{
abstract BaseController
abstract BaseCameraController
abstract BasePickerController
abstract BaseShortcutController
}
package Internal::Controller
{
class Freefly
class Trackball
class SelectionPicker
class GlobalShortcut
class VisualizationShortcut
class DebugShortcut
}
}
package Tool::Measurement::Controller
{
class MeasurementPicker
}
BaseController <|-- BaseCameraController
BaseController <|-- BasePickerController
BaseController <|-- BaseShortcutController
BaseCameraController <|-- Freefly
BaseCameraController <|-- Trackball
BasePickerController <|-- SelectionPicker
BasePickerController <|-- MeasurementPicker
BaseShortcutController <|-- GlobalShortcut
BaseShortcutController <|-- VisualizationShortcut
BaseShortcutController <|-- DebugShortcut
@enduml
```
### Animation (move to App ?)

Le module UI pourvoit un système d'animation. Le principe est de pouvoir lancer une succession d'animations sur un ou plusieurs objets afin de créer un petit film ou bien de modifier les données de certains objets sur une durée longue.

Pour cela, le système est composé d'une fonction BaseAnimation qui fourni le set minimale de fonction pour s'interfacer avec l'AnimationSystem afin de pouvoir jouer ou arrêter une animation.

Un set d'animation est disponible par défaut dans le dossier Internal/Animation. Il contient actuellement une animation de Translation ainsi que l'animation pour effectuer l'Orient et le Reset de la camera. La rotation des molécules pourrait aussi être ajoutée ici, mais il faudrait peut-être rajouter une fonctionnalité à l'AnimationSystème pour qu'il puisse plusieurs séquence d'animation en parallèle.

### Tools

2 changes: 2 additions & 0 deletions lib/app/include/app/application/system/serializer.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ namespace VTX::App::Application::System
class Serializer final : public System::AutoRegistrateSystem<Serializer>, public Core::Serialization::Serialization
{
public:
// Directly read a file at path p_path and deserialize it in p_obj object.
template<typename T>
void readObject( const FilePath & p_path, T & p_obj )
{
Expand All @@ -20,6 +21,7 @@ namespace VTX::App::Application::System
serializedObject.read();
}

// Directly serialize an object p_obj and write the json file at p_path
template<typename T>
void writeObject( const FilePath & p_path, const T & p_obj )
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,7 @@

namespace VTX::App::Application::System
{
// SystemRegistration is a class which must be declared as static member of any BaseSystem to automatically
// registrate itself to the SystemHandler
// Automating system registration to VTXApp systemHandler at launch when declared as static member of a BaseSystem
template<typename T>
class SystemRegistration
{
Expand All @@ -28,6 +27,7 @@ namespace VTX::App::Application::System
const Util::Hashing::Hash _hash;
};

// VTX systems must inherits from AutoRegistrateSystem<T> in order to registrate them directly in the SystemHandler
template<typename T>
class AutoRegistrateSystem : public Core::System::BaseSystem
{
Expand Down
3 changes: 2 additions & 1 deletion lib/app/include/app/application/system/threading.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,8 @@ namespace VTX::App::Application::System

namespace VTX::App
{
// Access to the worker manager class in order to launch thread.
Core::Worker::WorkerManager & THREADING();
}
} // namespace VTX::App

#endif
3 changes: 2 additions & 1 deletion lib/app/include/app/application/system/uid_system.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,8 @@ namespace VTX::App::Application::System

namespace VTX::App
{
// Access to UIDSystem to get / release UIDs.
Application::System::UIDSystem & UID_SYSTEM();
}
} // namespace VTX::App

#endif
13 changes: 9 additions & 4 deletions lib/python_binding/include/python_binding/wrapper/module.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
#include <pybind11/pybind11.h>
#include <string>
#include <util/exceptions.hpp>
#include <vector>

namespace VTX::PythonBinding
{
Expand Down Expand Up @@ -42,10 +43,12 @@ namespace VTX::PythonBinding
template<typename Func, typename... Extra>
void def( const std::string & p_name, Func p_function, const std::string & p_desc, Extra... p_extra )
{
_pyModule.def( p_name.c_str(),
p_function,
p_desc.c_str(),
Pybind11ExtraConvertor::convertToPybind11Extra( std::forward<Extra>( p_extra ) )... );
_pyModule.def(
p_name.c_str(),
p_function,
p_desc.c_str(),
Pybind11ExtraConvertor::convertToPybind11Extra( std::forward<Extra>( p_extra ) )...
);
}

void runFunction( const std::string & p_funcName ) const
Expand All @@ -66,6 +69,8 @@ namespace VTX::PythonBinding
void displayInfo() const;
const std::string & getModulePath() const { return _modulePath; }

std::vector<std::string> getFunctionList() const;

private:
Module( pybind11::module_ & p_module, const std::string & p_modulePath ) :
_pyModule( p_module ), _modulePath( p_modulePath )
Expand Down
25 changes: 25 additions & 0 deletions lib/python_binding/src/python_binding/wrapper/module.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -32,5 +32,30 @@ namespace VTX::PythonBinding::Wrapper
}
}

std::vector<std::string> Module::getFunctionList() const
{
std::vector<std::string> res = std::vector<std::string>();

try
{
auto dirObj = _pyModule.attr( "dir" );
auto direReturn = dirObj();
const pybind11::list commandList = direReturn.cast<pybind11::list>();

res.reserve( commandList.size() );

for ( const auto & value : commandList )
{
res.emplace_back( value.cast<std::string>() );
}
}
catch ( const pybind11::error_already_set & e )
{
VTX_ERROR( "getFunctionList fail : {}", e.what() );
}

return res;
}

Module::~Module() = default;
} // namespace VTX::PythonBinding::Wrapper
4 changes: 0 additions & 4 deletions lib/ui/conanfile.py
Original file line number Diff line number Diff line change
Expand Up @@ -109,10 +109,6 @@ def layout(self):

def generate(self):
tc = CMakeToolchain(self)
dir_python_script = self.dependencies["vtx_python_binding"].conf_info.get("user.myconf:dir_python_script")
tc.cache_variables["DIR_PYTHON_SCRIPT"] = dir_python_script
path_python_module = self.dependencies["vtx_python_binding"].conf_info.get("user.myconf:path_python_module")
tc.cache_variables["PATH_PYTHON_MODULE"] = path_python_module
tc.generate()

copy(self, "*.cmake", self.source_folder, self.build_folder)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,9 +23,11 @@ namespace VTX::UI::QT::Tool::PyTX::Widget
void _setupSlots() override;

private:
void _setupCompleter();
void _launchCommand();

QLineEdit * _promptWidget = nullptr;
QLineEdit * _promptWidget = nullptr;
QCompleter * _completer = nullptr;
};
} // namespace VTX::UI::QT::Tool::PyTX::Widget
#endif
14 changes: 0 additions & 14 deletions lib/ui/src/ui/qt/controller/camera_animation_controller.cpp

This file was deleted.

25 changes: 24 additions & 1 deletion lib/ui/src/ui/qt/tool/pytx/widget/command_line_prompt.cpp
Original file line number Diff line number Diff line change
@@ -1,12 +1,13 @@
#include "ui/qt/tool/pytx/widget/command_line_prompt.hpp"
#include "ui/qt/tool/pytx/details/include_python_binding.hpp"
#include <QCompleter>
#include <QHBoxLayout>
#include <QLabel>
#include <util/logger.hpp>

namespace VTX::UI::QT::Tool::PyTX::Widget
{
CommandLinePrompt::CommandLinePrompt( QWidget * p_parent ) : BaseManualWidget( p_parent ) {}
CommandLinePrompt::CommandLinePrompt( QWidget * p_parent ) : BaseManualWidget( p_parent ) { _setupCompleter(); }

void CommandLinePrompt::_setupUi( const QString & p_name )
{
Expand All @@ -19,6 +20,8 @@ namespace VTX::UI::QT::Tool::PyTX::Widget

_promptWidget = new QLineEdit( this );
_promptWidget->setPlaceholderText( "Write command here ( e.g. select( mol_n='1AGA' )" );

_promptWidget->setCompleter( _completer );
_promptWidget->setClearButtonEnabled( true );

QHBoxLayout * const horizontalLayout = new QHBoxLayout( this );
Expand Down Expand Up @@ -51,4 +54,24 @@ namespace VTX::UI::QT::Tool::PyTX::Widget

_promptWidget->clear();
}

void CommandLinePrompt::_setupCompleter()
{
// std::vector<std::string> allCommands = PythonBinding::INTERPRETOR().getModule().commands().getFunctionList();

QStringList strList = QStringList();

strList.emplaceBack( "resetCamera()" );
strList.emplaceBack( "quit()" );

// for ( const std::string & str : allCommands )
//{
// strList.emplaceBack( QString::fromStdString( str ) );
// }

_completer = new QCompleter( strList, this );
_completer->setCaseSensitivity( Qt::CaseSensitivity::CaseInsensitive );
_completer->setCompletionMode( QCompleter::CompletionMode::InlineCompletion );
}

} // namespace VTX::UI::QT::Tool::PyTX::Widget

0 comments on commit 979bf57

Please sign in to comment.