From f216f447abc690d837888622b89695aa25584dea Mon Sep 17 00:00:00 2001 From: aquiles Date: Tue, 2 Nov 2010 13:47:24 +0100 Subject: [PATCH] Added: Georges Editor Qt first revision --- code/ryzom/tools/leveldesign/CMakeLists.txt | 4 + .../georges_editor_qt/CMakeLists.txt | 19 + .../georges_editor_qt/data/georges_editor.cfg | 11 + .../data/georges_editor_default.cfg | 113 ++++ .../georges_editor_qt/src/CMakeLists.txt | 35 ++ .../georges_editor_qt/src/callback.cpp | 27 + .../georges_editor_qt/src/callback.h | 320 ++++++++++++ .../georges_editor_qt/src/configuration.cpp | 242 +++++++++ .../georges_editor_qt/src/configuration.h | 92 ++++ .../georges_editor_qt/src/entity.cpp | 269 ++++++++++ .../georges_editor_qt/src/entity.h | 217 ++++++++ .../src/filesystem_model.cpp | 70 +++ .../georges_editor_qt/src/filesystem_model.h | 43 ++ .../georges_editor_qt/src/formitem.cpp | 103 ++++ .../georges_editor_qt/src/formitem.h | 68 +++ .../georges_editor_qt/src/georges.cpp | 46 ++ .../georges_editor_qt/src/georges.h | 64 +++ .../src/georges_dirtree_dialog.cpp | 130 +++++ .../src/georges_dirtree_dialog.h | 64 +++ .../src/georges_dirtree_form.ui | 51 ++ .../src/georges_editor_qt.qrc | 13 + .../src/georges_treeview_dialog.cpp | 271 ++++++++++ .../src/georges_treeview_dialog.h | 80 +++ .../src/georges_treeview_form.ui | 122 +++++ .../src/georgesform_model.cpp | 442 ++++++++++++++++ .../georges_editor_qt/src/georgesform_model.h | 74 +++ .../src/georgesform_proxy_model.cpp | 56 ++ .../src/georgesform_proxy_model.h | 42 ++ .../georges_editor_qt/src/images/.directory | 3 + .../georges_editor_qt/src/images/go-down.png | Bin 0 -> 2404 bytes .../georges_editor_qt/src/images/go-up.png | Bin 0 -> 2426 bytes .../georges_editor_qt/src/images/khead.png | Bin 0 -> 1344 bytes .../georges_editor_qt/src/images/list-add.png | Bin 0 -> 2658 bytes .../src/images/list-remove.png | Bin 0 -> 1592 bytes .../georges_editor_qt/src/images/nel.png | Bin 0 -> 15587 bytes .../src/images/open-file.png | Bin 0 -> 1088 bytes .../src/images/pqrticles.png | Bin 0 -> 8318 bytes .../src/images/preferences.png | Bin 0 -> 10286 bytes .../georges_editor_qt/src/log_dialog.cpp | 58 +++ .../georges_editor_qt/src/log_dialog.h | 54 ++ .../georges_editor_qt/src/log_form.ui | 56 ++ .../georges_editor_qt/src/main.cpp | 116 +++++ .../georges_editor_qt/src/main_window.cpp | 488 ++++++++++++++++++ .../georges_editor_qt/src/main_window.h | 122 +++++ .../georges_editor_qt/src/modules.cpp | 44 ++ .../georges_editor_qt/src/modules.h | 44 ++ .../georges_editor_qt/src/object_viewer.cpp | 411 +++++++++++++++ .../georges_editor_qt/src/object_viewer.h | 191 +++++++ .../src/objectviewer_dialog.cpp | 408 +++++++++++++++ .../src/objectviewer_dialog.h | 108 ++++ .../src/objectviewer_form.ui | 28 + .../georges_editor_qt/src/qt_displayer.cpp | 113 ++++ .../georges_editor_qt/src/qt_displayer.h | 53 ++ .../georges_editor_qt/src/settings_dialog.cpp | 200 +++++++ .../georges_editor_qt/src/settings_dialog.h | 65 +++ .../georges_editor_qt/src/settings_form.ui | 227 ++++++++ .../georges_editor_qt/src/spindelegate.cpp | 275 ++++++++++ .../georges_editor_qt/src/spindelegate.h | 44 ++ .../georges_editor_qt/src/stdpch.cpp | 19 + .../georges_editor_qt/src/stdpch.h | 33 ++ 60 files changed, 6248 insertions(+) create mode 100644 code/ryzom/tools/leveldesign/georges_editor_qt/CMakeLists.txt create mode 100644 code/ryzom/tools/leveldesign/georges_editor_qt/data/georges_editor.cfg create mode 100644 code/ryzom/tools/leveldesign/georges_editor_qt/data/georges_editor_default.cfg create mode 100644 code/ryzom/tools/leveldesign/georges_editor_qt/src/CMakeLists.txt create mode 100644 code/ryzom/tools/leveldesign/georges_editor_qt/src/callback.cpp create mode 100644 code/ryzom/tools/leveldesign/georges_editor_qt/src/callback.h create mode 100644 code/ryzom/tools/leveldesign/georges_editor_qt/src/configuration.cpp create mode 100644 code/ryzom/tools/leveldesign/georges_editor_qt/src/configuration.h create mode 100644 code/ryzom/tools/leveldesign/georges_editor_qt/src/entity.cpp create mode 100644 code/ryzom/tools/leveldesign/georges_editor_qt/src/entity.h create mode 100644 code/ryzom/tools/leveldesign/georges_editor_qt/src/filesystem_model.cpp create mode 100644 code/ryzom/tools/leveldesign/georges_editor_qt/src/filesystem_model.h create mode 100644 code/ryzom/tools/leveldesign/georges_editor_qt/src/formitem.cpp create mode 100644 code/ryzom/tools/leveldesign/georges_editor_qt/src/formitem.h create mode 100644 code/ryzom/tools/leveldesign/georges_editor_qt/src/georges.cpp create mode 100644 code/ryzom/tools/leveldesign/georges_editor_qt/src/georges.h create mode 100644 code/ryzom/tools/leveldesign/georges_editor_qt/src/georges_dirtree_dialog.cpp create mode 100644 code/ryzom/tools/leveldesign/georges_editor_qt/src/georges_dirtree_dialog.h create mode 100644 code/ryzom/tools/leveldesign/georges_editor_qt/src/georges_dirtree_form.ui create mode 100644 code/ryzom/tools/leveldesign/georges_editor_qt/src/georges_editor_qt.qrc create mode 100644 code/ryzom/tools/leveldesign/georges_editor_qt/src/georges_treeview_dialog.cpp create mode 100644 code/ryzom/tools/leveldesign/georges_editor_qt/src/georges_treeview_dialog.h create mode 100644 code/ryzom/tools/leveldesign/georges_editor_qt/src/georges_treeview_form.ui create mode 100644 code/ryzom/tools/leveldesign/georges_editor_qt/src/georgesform_model.cpp create mode 100644 code/ryzom/tools/leveldesign/georges_editor_qt/src/georgesform_model.h create mode 100644 code/ryzom/tools/leveldesign/georges_editor_qt/src/georgesform_proxy_model.cpp create mode 100644 code/ryzom/tools/leveldesign/georges_editor_qt/src/georgesform_proxy_model.h create mode 100644 code/ryzom/tools/leveldesign/georges_editor_qt/src/images/.directory create mode 100644 code/ryzom/tools/leveldesign/georges_editor_qt/src/images/go-down.png create mode 100644 code/ryzom/tools/leveldesign/georges_editor_qt/src/images/go-up.png create mode 100644 code/ryzom/tools/leveldesign/georges_editor_qt/src/images/khead.png create mode 100644 code/ryzom/tools/leveldesign/georges_editor_qt/src/images/list-add.png create mode 100644 code/ryzom/tools/leveldesign/georges_editor_qt/src/images/list-remove.png create mode 100644 code/ryzom/tools/leveldesign/georges_editor_qt/src/images/nel.png create mode 100644 code/ryzom/tools/leveldesign/georges_editor_qt/src/images/open-file.png create mode 100644 code/ryzom/tools/leveldesign/georges_editor_qt/src/images/pqrticles.png create mode 100644 code/ryzom/tools/leveldesign/georges_editor_qt/src/images/preferences.png create mode 100644 code/ryzom/tools/leveldesign/georges_editor_qt/src/log_dialog.cpp create mode 100644 code/ryzom/tools/leveldesign/georges_editor_qt/src/log_dialog.h create mode 100644 code/ryzom/tools/leveldesign/georges_editor_qt/src/log_form.ui create mode 100644 code/ryzom/tools/leveldesign/georges_editor_qt/src/main.cpp create mode 100644 code/ryzom/tools/leveldesign/georges_editor_qt/src/main_window.cpp create mode 100644 code/ryzom/tools/leveldesign/georges_editor_qt/src/main_window.h create mode 100644 code/ryzom/tools/leveldesign/georges_editor_qt/src/modules.cpp create mode 100644 code/ryzom/tools/leveldesign/georges_editor_qt/src/modules.h create mode 100644 code/ryzom/tools/leveldesign/georges_editor_qt/src/object_viewer.cpp create mode 100644 code/ryzom/tools/leveldesign/georges_editor_qt/src/object_viewer.h create mode 100644 code/ryzom/tools/leveldesign/georges_editor_qt/src/objectviewer_dialog.cpp create mode 100644 code/ryzom/tools/leveldesign/georges_editor_qt/src/objectviewer_dialog.h create mode 100644 code/ryzom/tools/leveldesign/georges_editor_qt/src/objectviewer_form.ui create mode 100644 code/ryzom/tools/leveldesign/georges_editor_qt/src/qt_displayer.cpp create mode 100644 code/ryzom/tools/leveldesign/georges_editor_qt/src/qt_displayer.h create mode 100644 code/ryzom/tools/leveldesign/georges_editor_qt/src/settings_dialog.cpp create mode 100644 code/ryzom/tools/leveldesign/georges_editor_qt/src/settings_dialog.h create mode 100644 code/ryzom/tools/leveldesign/georges_editor_qt/src/settings_form.ui create mode 100644 code/ryzom/tools/leveldesign/georges_editor_qt/src/spindelegate.cpp create mode 100644 code/ryzom/tools/leveldesign/georges_editor_qt/src/spindelegate.h create mode 100644 code/ryzom/tools/leveldesign/georges_editor_qt/src/stdpch.cpp create mode 100644 code/ryzom/tools/leveldesign/georges_editor_qt/src/stdpch.h diff --git a/code/ryzom/tools/leveldesign/CMakeLists.txt b/code/ryzom/tools/leveldesign/CMakeLists.txt index 0e49fedf0..37489d924 100644 --- a/code/ryzom/tools/leveldesign/CMakeLists.txt +++ b/code/ryzom/tools/leveldesign/CMakeLists.txt @@ -9,6 +9,10 @@ IF(WIN32) ADD_SUBDIRECTORY(world_editor) ENDIF(WIN32) +IF(WITH_QT) + ADD_SUBDIRECTORY(georges_editor_qt) +ENDIF(WITH_QT) + # folders not handled yet. #georges_convert #georges_dll diff --git a/code/ryzom/tools/leveldesign/georges_editor_qt/CMakeLists.txt b/code/ryzom/tools/leveldesign/georges_editor_qt/CMakeLists.txt new file mode 100644 index 000000000..0354cbeeb --- /dev/null +++ b/code/ryzom/tools/leveldesign/georges_editor_qt/CMakeLists.txt @@ -0,0 +1,19 @@ +#----------------------------------------------------------------------------- +# +# Georges Editor Qt +# Copyright (C) 2010 Adrian Jäkel +# +#----------------------------------------------------------------------------- + +# This tells the application(s) where to find the installed data. +ADD_DEFINITIONS(-DDATA_DIR="\\"${NL_SHARE_PREFIX}/georges_editor_qt/\\"") + +ADD_SUBDIRECTORY(src) + +INSTALL(DIRECTORY data/ + DESTINATION share/georges_editor_qt/data + COMPONENT data + PATTERN "CVS" EXCLUDE + PATTERN ".svn" EXCLUDE + PATTERN "Makefile*" EXCLUDE) + diff --git a/code/ryzom/tools/leveldesign/georges_editor_qt/data/georges_editor.cfg b/code/ryzom/tools/leveldesign/georges_editor_qt/data/georges_editor.cfg new file mode 100644 index 000000000..ebea3b459 --- /dev/null +++ b/code/ryzom/tools/leveldesign/georges_editor_qt/data/georges_editor.cfg @@ -0,0 +1,11 @@ +RootConfigFilename = "georges_editor_default.cfg"; +SearchPaths = { + "G:/ryzom_assets/ryzom_assets/Stuff/Matis", "G:/ryzom_assets/bnps/characters_shapes" +}; +GraphicsDriver = "OpenGL"; +BackgroundColor = { + 173, 205, 234 +}; +LeveldesignPath = "D:/Dev/Ryzom/code/ryzom/common/data_leveldesign/leveldesign"; +QtWindowState = "%00%00%00%FF%00%00%00%00%FD%00%00%00%03%00%00%00%00%00%00%02%A6%00%00%00%E9%FC%02%00%00%00%01%FB%00%00%00%2A%00C%00G%00e%00o%00r%00g%00e%00s%00D%00i%00r%00T%00r%00e%00e%00D%00i%00a%00l%00o%00g%01%00%00%00%3B%00%00%00%E9%00%00%00t%00%FF%FF%FF%00%00%00%02%00%00%00%00%00%00%00%00%FC%01%00%00%00%01%FB%00%00%00%26%00C%00O%00b%00j%00e%00c%00t%00V%00i%00e%00w%00e%00r%00D%00i%00a%00l%00o%00g%00%00%00%00%00%FF%FF%FF%FF%00%00%00N%00%FF%FF%FF%00%00%00%03%00%00%02%A6%00%00%01c%FC%01%00%00%00%01%FB%00%00%00%22%00C%00G%00e%00o%00r%00g%00e%00s%00L%00o%00g%00D%00i%00a%00l%00o%00g%01%00%00%00%00%00%00%02%A6%00%00%00%5D%00%FF%FF%FF%00%00%00%00%00%00%00%E9%00%00%00%04%00%00%00%04%00%00%00%08%00%00%00%08%FC%00%00%00%01%00%00%00%02%00%00%00%01%FF%FF%FF%FF%01%00%00%00%00%FF%FF%FF%FF%00%00%00%00%00%00%00%00"; +QtWindowGeometry = "%01%D9%D0%CB%00%01%00%00%00%00%00%D6%00%00%00%C0%00%00%03%83%00%00%03%82%00%00%00%DA%00%00%00%DE%00%00%03%7F%00%00%03~%00%00%00%00%00%00"; diff --git a/code/ryzom/tools/leveldesign/georges_editor_qt/data/georges_editor_default.cfg b/code/ryzom/tools/leveldesign/georges_editor_qt/data/georges_editor_default.cfg new file mode 100644 index 000000000..93343bce4 --- /dev/null +++ b/code/ryzom/tools/leveldesign/georges_editor_qt/data/georges_editor_default.cfg @@ -0,0 +1,113 @@ +////////////////////////////////////////////////////////////////////////////// +// Config file for Georges Editor Qt //////////////////////////////////////////////////// +////////////////////////////////////////////////////////////////////////////// + +// +// This file is used to setup the georges editor tool. +// + + +////////////////////////////////////////////////////////////////////////////// +// NeL Qt //////////////////////////////////////////////////////////////////// +////////////////////////////////////////////////////////////////////////////// + +// Root directory where we can find the client datas (zones, tiles, maps, ...) +// You must uncomment this line on GNU/Linux and comment the next one +//SearchPaths = { "/usr/local/share/games/nel_qt/" }; +SearchPaths = { "data" }; +LeveldesignPath = ""; + +// Which extensions to remap to what if needed (pairs of 2) +RemapExtensions = { "png", "tga" }; + +// The language code of the client +LanguageCode = "en"; + +// If changes to the config should be saved on exit +SaveConfig = 1; + + +////////////////////////////////////////////////////////////////////////////// +// Qt //////////////////////////////////////////////////////////////////////// +////////////////////////////////////////////////////////////////////////////// + +QtStyle = "Cleanlooks"; +QtPalette = 0; +QtWindowState = ""; +QtWindowGeometry = ""; + +////////////////////////////////////////////////////////////////////////////// +// Graphics ////////////////////////////////////////////////////////////////// +////////////////////////////////////////////////////////////////////////////// + +// Use OpenGL or Direct3D (Windows) +GraphicsEnabled = 1; +GraphicsDrivers = { "OpenGL", "Direct3D" }; +GraphicsDriver = "OpenGL"; + +// Font name used for all text in the client (it can be a .ttf, .fon, .pfb) +FontName = "andbasr.ttf"; +FontShadow = 1; + +// Background color +BackgroundColor = { 151, 156, 182 }; + +SunDirection = { -2.935, +0.107, -1.22 }; +SunAmbient = { 190, 170, 150 }; +SunDiffuse = { 255, 248, 255 }; +SunSpecular = { 255, 255, 255}; + +////////////////////////////////////////////////////////////////////////////// +// Time ////////////////////////////////////////////////////////////////////// +////////////////////////////////////////////////////////////////////////////// + +FpsSmoothing = 64; + +////////////////////////////////////////////////////////////////////////////// +// Interface ///////////////////////////////////////////////////////////////// +////////////////////////////////////////////////////////////////////////////// + +// This setting is used to bind keys to actions. +// "key_handler", "args", "***", "Key1|Key2", +// *** -> CTRL, SHIFT, ALT don't matter +// --- -> CTRL, SHIFT, ALT must all be disabled +// -+- -> only SHIFT must be down +KeySettings = { + "screenshot", "", "***", "KeyF5", + "command", "set_state Exit", "-+-", "KeyESCAPE", + "command", "set_state Login", "+--", "KeyESCAPE", + "command", "set_state Unload", "***", "KeyF8", + "command", "set_state Demo", "***", "KeyF7", + "move_forward", "", "***", "KeyUP|KeyZ|KeyW", + "move_backward", "", "***", "KeyDOWN|KeyS", + "move_left", "", "***", "KeyLEFT|KeyQ|KeyA", + "move_right", "", "***", "KeyRIGHT|KeyD", + "move_forward", "", "***", "KeyZ|KeyW", + "move_backward", "", "***", "KeyS", + "move_left", "", "***", "KeyQ|KeyA", + "move_right", "", "***", "KeyD", + "chat_begin", "", "***", "KeyT", + "chat_send", "", "***", "KeyENTER", + "chat_leave", "", "***", "KeyESCAPE", + "display_test", "", "***", "KeyTAB", + "send_action", "0", "---", "Key1", + "send_action", "1", "---", "Key2", + "send_action", "2", "---", "Key3", + "send_action", "3", "---", "Key4", + "send_action", "4", "---", "Key5", + "send_action", "5", "---", "Key6", + "send_action", "6", "---", "Key7", + "send_action", "7", "---", "Key8", + "send_action", "8", "---", "Key9", + "send_action", "9", "---", "Key0", + "demo_crystal_spawn", "", "---", "KeyO", + "demo_crystal_explode", "", "---", "KeyP", + "free_camera_forward", "", "---", "KeyNUMPAD8", + "free_camera_backward", "", "---", "KeyNUMPAD2", + "free_camera_left", "", "---", "KeyNUMPAD4", + "free_camera_right", "", "---", "KeyNUMPAD6", + "switch_camera", "", "---", "KeyF4", + "switch_ui_visible" ,"", "---", "KeyF6", +}; + +// end of file diff --git a/code/ryzom/tools/leveldesign/georges_editor_qt/src/CMakeLists.txt b/code/ryzom/tools/leveldesign/georges_editor_qt/src/CMakeLists.txt new file mode 100644 index 000000000..9c4f37aaf --- /dev/null +++ b/code/ryzom/tools/leveldesign/georges_editor_qt/src/CMakeLists.txt @@ -0,0 +1,35 @@ +INCLUDE_DIRECTORIES(${CMAKE_CURRENT_BINARY_DIR} ${CMAKE_CURRENT_SOURCE_DIR} ${LIBXML2_INCLUDE_DIR} ${NEL_INCLUDE_DIR} ${QT_INCLUDES}) +INCLUDE( ${QT_USE_FILE} ) + +FILE(GLOB GEORGES_EDITOR_SRC *.cpp) +SET(GEORGES_EDITOR_HDR georges_dirtree_dialog.h georges_treeview_dialog.h georgesform_model.h main_window.h + log_dialog.h objectviewer_dialog.h settings_dialog.h) +SET(GEORGES_EDITOR_UIS settings_form.ui objectviewer_form.ui log_form.ui georges_treeview_form.ui georges_dirtree_form.ui) +SET(GEORGES_EDITOR_RCS georges_editor_qt.qrc) + +SET(QT_USE_QTGUI TRUE) +SET(QT_USE_QTOPENGL TRUE) + +QT4_ADD_RESOURCES( GEORGES_EDITOR_RC_SRCS ${GEORGES_EDITOR_RCS} ) +QT4_WRAP_CPP( GEORGES_EDITOR_MOC_SRCS ${GEORGES_EDITOR_HDR} ) +QT4_WRAP_UI( GEORGES_EDITOR_UI_HDRS ${GEORGES_EDITOR_UIS} ) + +ADD_EXECUTABLE(georges_editor_qt WIN32 ${GEORGES_EDITOR_SRC} ${GEORGES_EDITOR_MOC_SRCS} ${GEORGES_EDITOR_RC_SRCS} ${GEORGES_EDITOR_UI_HDRS}) + +TARGET_LINK_LIBRARIES(georges_editor_qt + nelmisc + nel3d + nelgeorges + ${QT_LIBRARIES} + ${QT_QTOPENGL_LIBRARY} + ${QT_QTMAIN_LIBRARY}) + +ADD_DEFINITIONS(-DQT_NO_KEYWORDS ${LIBXML2_DEFINITIONS} ${QT_DEFINITIONS}) +NL_DEFAULT_PROPS(georges_editor_qt "Ryzom, Tools, World: Georges Editor Qt") +NL_ADD_RUNTIME_FLAGS(georges_editor_qt) + +IF(WITH_PCH) + ADD_NATIVE_PRECOMPILED_HEADER(georges_editor_qt ${CMAKE_CURRENT_SOURCE_DIR}/stdpch.h ${CMAKE_CURRENT_SOURCE_DIR}/stdpch.cpp) +ENDIF(WITH_PCH) + +INSTALL(TARGETS georges_editor_qt RUNTIME DESTINATION bin COMPONENT runtime) diff --git a/code/ryzom/tools/leveldesign/georges_editor_qt/src/callback.cpp b/code/ryzom/tools/leveldesign/georges_editor_qt/src/callback.cpp new file mode 100644 index 000000000..c09c6e357 --- /dev/null +++ b/code/ryzom/tools/leveldesign/georges_editor_qt/src/callback.cpp @@ -0,0 +1,27 @@ +/* + * Copyright (C) 2010 by authors + * + * This file is part of NEL QT. + * NEL QT is free software: you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * NEL QT is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with NEL QT; see the file COPYING. If not, see + * . + */ + +#include +#include "callback.h" + +namespace NLQT { + +} /* namespace NLQT */ + +/* end of file */ diff --git a/code/ryzom/tools/leveldesign/georges_editor_qt/src/callback.h b/code/ryzom/tools/leveldesign/georges_editor_qt/src/callback.h new file mode 100644 index 000000000..eba33d564 --- /dev/null +++ b/code/ryzom/tools/leveldesign/georges_editor_qt/src/callback.h @@ -0,0 +1,320 @@ +/* + * Copyright (C) 2010 by authors + * + * This file is part of NEL QT. + * NEL QT is free software: you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * NEL QT is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with NEL QT; see the file COPYING. If not, see + * . + */ + +#ifndef NLQT_CALLBACK_H +#define NLQT_CALLBACK_H +#include + +// STL includes + +// NeL includes +#include + +// Project includes + +namespace NLQT { + +#define NLQT_CALLBACK_TEMPLATE \ +/** \ + * \brief NLQT_CALLBACK_ARGS_CLASS \ + * \date 2009-03-03 18:09GMT \ + * \author Jan Boon (Kaetemi) \ + * Awesome callback template \ + */ \ +template \ +class NLQT_CALLBACK_ARGS_CLASS \ +{ \ + /* Very simple reference counting callback base */ \ + class CCallbackBase \ + { \ + public: \ + CCallbackBase() : m_RefCount(0) \ + { \ + \ + } \ + \ + virtual ~CCallbackBase() \ + { \ + nlassert(!m_RefCount); \ + } \ + \ + void refAdd() \ + { \ + ++m_RefCount; \ + } \ + \ + void refRemove() \ + { \ + --m_RefCount; \ + if (!m_RefCount) \ + delete this; \ + } \ + \ + virtual TReturn callback(NLQT_CALLBACK_ARGS_DECL) = 0; \ + \ + virtual bool equals(const CCallbackBase *callbackBase) = 0; \ + \ + /* disable copy */ \ + CCallbackBase(const CCallbackBase &); \ + CCallbackBase &operator=(const CCallbackBase &); \ + \ + private: \ + uint m_RefCount; \ + }; \ + \ + typedef TReturn TCallbackFunction(NLQT_CALLBACK_ARGS_DECL); \ + class CCallbackFunction : public CCallbackBase \ + { \ + public: \ + CCallbackFunction(TCallbackFunction *callbackFunction) : m_CallbackFunction(callbackFunction) \ + { \ + nlassert(m_CallbackFunction); \ + } \ + \ + virtual ~CCallbackFunction() \ + { \ + m_CallbackFunction = NULL; \ + } \ + \ + virtual TReturn callback(NLQT_CALLBACK_ARGS_DECL) \ + { \ + return m_CallbackFunction(NLQT_CALLBACK_ARGS_IMPL); \ + } \ + \ + virtual bool equals(const CCallbackBase *callbackBase) \ + { \ + const CCallbackFunction *callbackFunction = \ + dynamic_cast(callbackBase); \ + if (!callbackFunction) return false; \ + return m_CallbackFunction == callbackFunction->m_CallbackFunction; \ + } \ + \ + private: \ + TCallbackFunction *m_CallbackFunction; \ + }; \ + \ + template \ + class CCallbackMethod : public CCallbackBase \ + { \ + typedef TReturn (TClass::*TCallbackMethod)(NLQT_CALLBACK_ARGS_DECL); \ + public: \ + CCallbackMethod(TClass *callbackObject, TCallbackMethod callbackMethod) : m_CallbackObject(callbackObject), m_CallbackMethod(callbackMethod) \ + { \ + nlassert(m_CallbackObject); \ + nlassert(m_CallbackMethod); \ + } \ + \ + virtual ~CCallbackMethod() \ + { \ + m_CallbackObject = NULL; \ + m_CallbackMethod = NULL; \ + } \ + \ + virtual TReturn callback(NLQT_CALLBACK_ARGS_DECL) \ + { \ + return (m_CallbackObject->*m_CallbackMethod)(NLQT_CALLBACK_ARGS_IMPL); \ + } \ + \ + virtual bool equals(const CCallbackBase *callbackBase) \ + { \ + const CCallbackMethod *callbackMethod = \ + dynamic_cast(callbackBase); \ + if (!callbackMethod) return false; \ + return m_CallbackObject == callbackMethod->m_CallbackObject \ + && m_CallbackMethod == callbackMethod->m_CallbackMethod; \ + } \ + \ + private: \ + TClass *m_CallbackObject; \ + TCallbackMethod m_CallbackMethod; \ + }; \ + \ +public: \ + CCallback() : m_CallbackBase(NULL) \ + { \ + \ + } \ + \ + CCallback(TCallbackFunction *callbackFunction) : m_CallbackBase(new CCallbackFunction(callbackFunction)) \ + { \ + nlassert(m_CallbackBase); \ + m_CallbackBase->refAdd(); \ + } \ + \ + template \ + CCallback(TClass *callbackObject, TReturn (TClass::*callbackMethod)(NLQT_CALLBACK_ARGS_DECL)) : m_CallbackBase(new CCallbackMethod(callbackObject, callbackMethod)) \ + { \ + nlassert(m_CallbackBase); \ + m_CallbackBase->refAdd(); \ + } \ + \ + CCallback(const CCallback &callback) \ + { \ + m_CallbackBase = callback.m_CallbackBase; \ + if (m_CallbackBase) \ + m_CallbackBase->refAdd(); \ + } \ + \ + CCallback &operator=(const CCallback &callback) \ + { \ + if (m_CallbackBase != callback.m_CallbackBase) \ + { \ + if (m_CallbackBase) \ + m_CallbackBase->refRemove(); \ + m_CallbackBase = callback.m_CallbackBase; \ + if (m_CallbackBase) \ + m_CallbackBase->refAdd(); \ + } \ + return *this; \ + } \ + \ + ~CCallback() \ + { \ + if (m_CallbackBase) \ + { \ + m_CallbackBase->refRemove(); \ + m_CallbackBase = NULL; \ + } \ + } \ + \ + TReturn callback(NLQT_CALLBACK_ARGS_DECL) \ + { \ + nlassert(m_CallbackBase); \ + return m_CallbackBase->callback(NLQT_CALLBACK_ARGS_IMPL); \ + } \ + \ + TReturn operator()(NLQT_CALLBACK_ARGS_DECL) \ + { \ + nlassert(m_CallbackBase); \ + return m_CallbackBase->callback(NLQT_CALLBACK_ARGS_IMPL); \ + } \ + \ + bool valid() const \ + { \ + return m_CallbackBase != NULL; \ + } \ + \ + operator bool() const \ + { \ + return m_CallbackBase != NULL; \ + } \ + \ + bool operator==(const CCallback &callback) \ + { \ + return m_CallbackBase->equals(callback.m_CallbackBase); \ + } \ + \ +private: \ + CCallbackBase *m_CallbackBase; \ + \ +}; /* class CCallback */ \ + +template +class CCallback; + +#define NLQT_CALLBACK_ARGS_CLASS CCallback +#define NLQT_CALLBACK_ARGS_TYPENAME +#define NLQT_CALLBACK_ARGS_DECL +#define NLQT_CALLBACK_ARGS_IMPL +NLQT_CALLBACK_TEMPLATE +#undef NLQT_CALLBACK_ARGS_CLASS +#undef NLQT_CALLBACK_ARGS_TYPENAME +#undef NLQT_CALLBACK_ARGS_DECL +#undef NLQT_CALLBACK_ARGS_IMPL + +#define NLQT_CALLBACK_ARGS_CLASS CCallback +#define NLQT_CALLBACK_ARGS_TYPENAME , typename TArgsA +#define NLQT_CALLBACK_ARGS_DECL TArgsA argsA +#define NLQT_CALLBACK_ARGS_IMPL argsA +NLQT_CALLBACK_TEMPLATE +#undef NLQT_CALLBACK_ARGS_CLASS +#undef NLQT_CALLBACK_ARGS_TYPENAME +#undef NLQT_CALLBACK_ARGS_DECL +#undef NLQT_CALLBACK_ARGS_IMPL + +#define NLQT_CALLBACK_ARGS_CLASS CCallback +#define NLQT_CALLBACK_ARGS_TYPENAME , typename TArgsA, typename TArgsB +#define NLQT_CALLBACK_ARGS_DECL TArgsA argsA, TArgsB argsB +#define NLQT_CALLBACK_ARGS_IMPL argsA, argsB +NLQT_CALLBACK_TEMPLATE +#undef NLQT_CALLBACK_ARGS_CLASS +#undef NLQT_CALLBACK_ARGS_TYPENAME +#undef NLQT_CALLBACK_ARGS_DECL +#undef NLQT_CALLBACK_ARGS_IMPL + +#define NLQT_CALLBACK_ARGS_CLASS CCallback +#define NLQT_CALLBACK_ARGS_TYPENAME , typename TArgsA, typename TArgsB, typename TArgsC +#define NLQT_CALLBACK_ARGS_DECL TArgsA argsA, TArgsB argsB, TArgsC argsC +#define NLQT_CALLBACK_ARGS_IMPL argsA, argsB, argsC +NLQT_CALLBACK_TEMPLATE +#undef NLQT_CALLBACK_ARGS_CLASS +#undef NLQT_CALLBACK_ARGS_TYPENAME +#undef NLQT_CALLBACK_ARGS_DECL +#undef NLQT_CALLBACK_ARGS_IMPL + +#define NLQT_CALLBACK_ARGS_CLASS CCallback +#define NLQT_CALLBACK_ARGS_TYPENAME , typename TArgsA, typename TArgsB, typename TArgsC, typename TArgsD +#define NLQT_CALLBACK_ARGS_DECL TArgsA argsA, TArgsB argsB, TArgsC argsC, TArgsD argsD +#define NLQT_CALLBACK_ARGS_IMPL argsA, argsB, argsC, argsD +NLQT_CALLBACK_TEMPLATE +#undef NLQT_CALLBACK_ARGS_CLASS +#undef NLQT_CALLBACK_ARGS_TYPENAME +#undef NLQT_CALLBACK_ARGS_DECL +#undef NLQT_CALLBACK_ARGS_IMPL + +#define NLQT_CALLBACK_ARGS_CLASS CCallback +#define NLQT_CALLBACK_ARGS_TYPENAME , typename TArgsA, typename TArgsB, typename TArgsC, typename TArgsD, typename TArgsE +#define NLQT_CALLBACK_ARGS_DECL TArgsA argsA, TArgsB argsB, TArgsC argsC, TArgsD argsD, TArgsE argsE +#define NLQT_CALLBACK_ARGS_IMPL argsA, argsB, argsC, argsD, argsE +NLQT_CALLBACK_TEMPLATE +#undef NLQT_CALLBACK_ARGS_CLASS +#undef NLQT_CALLBACK_ARGS_TYPENAME +#undef NLQT_CALLBACK_ARGS_DECL +#undef NLQT_CALLBACK_ARGS_IMPL + +#define NLQT_CALLBACK_ARGS_CLASS CCallback +#define NLQT_CALLBACK_ARGS_TYPENAME , typename TArgsA, typename TArgsB, typename TArgsC, typename TArgsD, typename TArgsE, typename TArgsF +#define NLQT_CALLBACK_ARGS_DECL TArgsA argsA, TArgsB argsB, TArgsC argsC, TArgsD argsD, TArgsE argsE, TArgsF argsF +#define NLQT_CALLBACK_ARGS_IMPL argsA, argsB, argsC, argsD, argsE, argsF +NLQT_CALLBACK_TEMPLATE +#undef NLQT_CALLBACK_ARGS_CLASS +#undef NLQT_CALLBACK_ARGS_TYPENAME +#undef NLQT_CALLBACK_ARGS_DECL +#undef NLQT_CALLBACK_ARGS_IMPL + +#define NLQT_CALLBACK_ARGS_CLASS CCallback +#define NLQT_CALLBACK_ARGS_TYPENAME , typename TArgsA, typename TArgsB, typename TArgsC, typename TArgsD, typename TArgsE, typename TArgsF, typename TArgsG +#define NLQT_CALLBACK_ARGS_DECL TArgsA argsA, TArgsB argsB, TArgsC argsC, TArgsD argsD, TArgsE argsE, TArgsF argsF, TArgsG argsG +#define NLQT_CALLBACK_ARGS_IMPL argsA, argsB, argsC, argsD, argsE, argsF, argsG +NLQT_CALLBACK_TEMPLATE +#undef NLQT_CALLBACK_ARGS_CLASS +#undef NLQT_CALLBACK_ARGS_TYPENAME +#undef NLQT_CALLBACK_ARGS_DECL +#undef NLQT_CALLBACK_ARGS_IMPL +#undef NLQT_CALLBACK_ARGS_CLASSNAME + +#undef NLQT_CALLBACK_TEMPLATE + +typedef CCallback CEmptyCallback; + +} /* namespace NLQT */ + +#endif /* #ifndef NLQT_CALLBACK_H */ + +/* end of file */ diff --git a/code/ryzom/tools/leveldesign/georges_editor_qt/src/configuration.cpp b/code/ryzom/tools/leveldesign/georges_editor_qt/src/configuration.cpp new file mode 100644 index 000000000..2276dcd93 --- /dev/null +++ b/code/ryzom/tools/leveldesign/georges_editor_qt/src/configuration.cpp @@ -0,0 +1,242 @@ +/* + Georges Editor Qt + Copyright (C) 2010 Adrian Jaekel + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + +*/ + +#include "configuration.h" + +// STL includes + +// Qt includes +#include + +// NeL includes +#include +#include +#include +#include + +#include "modules.h" + +#include + +using namespace std; +using namespace NLMISC; + +namespace NLQT { + +CConfiguration::CConfiguration() +{ + +} + +CConfiguration::~CConfiguration() +{ + +} + +void CConfiguration::init() +{ + // verify data + nlassert(!ConfigCallbacks.size()); + + // load config + QFile file(NLQT_CONFIG_FILE); + if (!file.exists()) { + file.open( QIODevice::WriteOnly | QIODevice::Text ); + file.write("GraphicsDrivers = { \"OpenGL\", \"Direct3D\" };"); + file.write("\nSearchPaths = {\"\"};"); + file.write("\nRemapExtensions = { \"png\", \"tga\" };"); + file.write("\nBackgroundColor = { 0, 0, 0 };"); + file.write("\nQtStyle = \"\";"); + file.write("\nQtPalette = \"\";"); + file.close(); + } + + try { + ConfigFile.load(NLQT_CONFIG_FILE); + } catch(...) { + } + + // setup config file callback + Modules::config().setCallback("SearchPaths", CConfigCallback(this, &CConfiguration::cfcbSearchPaths)); + +} + +void CConfiguration::release() +{ + Modules::config().dropCallback("SearchPaths"); + + // save and release the config file + if (ConfigFile.exists("SaveConfig") && ConfigFile.getVarPtr("SaveConfig")->asBool()) + { + ConfigFile.save(); + } + ConfigFile.clear(); + + // release the search paths etc + CPath::releaseInstance(); + + // verify data + nlassert(!ConfigCallbacks.size()); +} + +void CConfiguration::updateUtilities() +{ + //H_AUTO2 + CConfigFile::checkConfigFiles(); +} + +void CConfiguration::configSearchPaths() +{ + cfcbSearchPaths(Modules::config().getConfigFile().getVar("SearchPaths")); +} + +std::string CConfiguration::configLeveldesignPath() +{ + std::string path = Modules::config().getValue("LeveldesignPath", QString("").toStdString()); + cfcbSearchPaths(Modules::config().getConfigFile().getVar("LeveldesignPath")); + + return path; +} + +void CConfiguration::configRemapExtensions() +{ + CConfigFile::CVar *var; + var = ConfigFile.getVarPtr("RemapExtensions"); + uint varsize = var->size(); + for (uint i = 0; i < varsize; i += 2) + CPath::remapExtension(var->asString(i), var->asString(i + 1), true); +} + +void CConfiguration::setAndCallback(const std::string &varName, CConfigCallback configCallback) +{ + ConfigCallbacks[varName] = configCallback; + ConfigFile.setCallback(varName, cbConfigCallback); + configCallback(*ConfigFile.getVarPtr(varName)); +} + +void CConfiguration::setCallback(const std::string &varName, CConfigCallback configCallback) +{ + ConfigCallbacks[varName] = configCallback; + ConfigFile.setCallback(varName, cbConfigCallback); +} + +void CConfiguration::dropCallback(const std::string &varName) +{ + ConfigFile.setCallback(varName, NULL); + ConfigCallbacks.erase(varName); +} + +float CConfiguration::getValue(const string &varName, float defaultValue) +{ + if (ConfigFile.exists(varName)) return ConfigFile.getVar(varName).asFloat(); + CConfigFile::CVar varToCopy; + varToCopy.forceAsDouble((double)defaultValue); + ConfigFile.insertVar(varName, varToCopy); + return defaultValue; +} + +double CConfiguration::getValue(const string &varName, double defaultValue) +{ + if (ConfigFile.exists(varName)) return ConfigFile.getVar(varName).asDouble(); + CConfigFile::CVar varToCopy; + varToCopy.forceAsDouble(defaultValue); + ConfigFile.insertVar(varName, varToCopy); + return defaultValue; +} + +int CConfiguration::getValue(const string &varName, int defaultValue) +{ + if (ConfigFile.exists(varName)) return ConfigFile.getVar(varName).asInt(); + CConfigFile::CVar varToCopy; + varToCopy.forceAsInt(defaultValue); + ConfigFile.insertVar(varName, varToCopy); + return defaultValue; +} + +string CConfiguration::getValue(const string &varName, const string &defaultValue) +{ + if (ConfigFile.exists(varName)) return ConfigFile.getVar(varName).asString(); + CConfigFile::CVar varToCopy; + varToCopy.forceAsString(defaultValue); + ConfigFile.insertVar(varName, varToCopy); + return defaultValue; +} + +ucstring CConfiguration::getValue(const string &varName, const ucstring &defaultValue) +{ + if (ConfigFile.exists(varName)) return ucstring::makeFromUtf8(ConfigFile.getVar(varName).asString()); + CConfigFile::CVar varToCopy; + varToCopy.forceAsString(defaultValue.toUtf8()); + ConfigFile.insertVar(varName, varToCopy); + return defaultValue; +} + +bool CConfiguration::getValue(const string &varName, bool defaultValue) +{ + if (ConfigFile.exists(varName)) return ConfigFile.getVar(varName).asBool(); + CConfigFile::CVar varToCopy; + varToCopy.forceAsInt(defaultValue ? 1 : 0); + ConfigFile.insertVar(varName, varToCopy); + return defaultValue; +} + +CRGBA CConfiguration::getValue(const string &varName, const CRGBA &defaultValue) +{ + if (ConfigFile.exists(varName)) + { + return getValue(ConfigFile.getVar(varName), defaultValue); + } + else + { + // create a new value only if one doesn't exist + CConfigFile::CVar varToCopy; + varToCopy.forceAsInt(defaultValue.R); + varToCopy.setAsInt(defaultValue.G, 1); + varToCopy.setAsInt(defaultValue.B, 2); + varToCopy.setAsInt(defaultValue.A, 3); + ConfigFile.insertVar(varName, varToCopy); + } + return defaultValue; +} + +CRGBA CConfiguration::getValue(const CConfigFile::CVar &var, const CRGBA &defaultValue) +{ + if (var.size() >= 3) + { + if (var.size() > 4) nlwarning("RGBA value in config value '%s' is too long, ignoring unused values"); + return CRGBA((uint8)var.asInt(0), (uint8)var.asInt(1), (uint8)var.asInt(2), var.size() >= 4 ? (uint8)var.asInt(3) : 255); + } + nlwarning("Invalid RGBA value in config value '%s', reverting to default { %i, %i, %i, %i }", var.Name.c_str(), (sint)defaultValue.R, (sint)defaultValue.G, (sint)defaultValue.B, (sint)defaultValue.A); + return defaultValue; +} + +void CConfiguration::cbConfigCallback(NLMISC::CConfigFile::CVar &var) +{ + Modules::config().ConfigCallbacks[var.Name](var); +} + +void CConfiguration::cfcbSearchPaths(NLMISC::CConfigFile::CVar &var) +{ + uint varsize = var.size(); + //CPath::clearMap(); + for (uint i = 0; i < varsize; ++i) + CPath::addSearchPath(var.asString(i), true, false); +} + +} /* namespace NLQT */ \ No newline at end of file diff --git a/code/ryzom/tools/leveldesign/georges_editor_qt/src/configuration.h b/code/ryzom/tools/leveldesign/georges_editor_qt/src/configuration.h new file mode 100644 index 000000000..5acedd7a5 --- /dev/null +++ b/code/ryzom/tools/leveldesign/georges_editor_qt/src/configuration.h @@ -0,0 +1,92 @@ +/* + Georges Editor Qt + Copyright (C) 2010 Adrian Jaekel + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + +*/ + +#ifndef CONFIGURATION_H +#define CONFIGURATION_H + +#include + +// STL includes +#include + +// NeL includes +#include +#include +#include + +// Project includes +#include "callback.h" + +#define NLQT_CONFIG_FILE "georges_editor.cfg" + +namespace NLQT { + +typedef CCallback CConfigCallback; + +/** + * CConfiguration + * \brief CConfiguration + * \date 2010-02-05 15:44GMT + * \author Jan Boon (Kaetemi) + */ +class CConfiguration +{ +public: + CConfiguration(); + virtual ~CConfiguration(); + + void init(); + void release(); + + void updateUtilities(); + void configSearchPaths(); + std::string configLeveldesignPath(); + void configRemapExtensions(); + + void setAndCallback(const std::string &varName, CConfigCallback configCallback); + void setCallback(const std::string &varName, CConfigCallback configCallback); + void dropCallback(const std::string &varName); + + float getValue(const std::string &varName, float defaultValue); + double getValue(const std::string &varName, double defaultValue); + int getValue(const std::string &varName, int defaultValue); + std::string getValue(const std::string &varName, const std::string &defaultValue); + ucstring getValue(const std::string &varName, const ucstring &defaultValue); + bool getValue(const std::string &varName, bool defaultValue); + NLMISC::CRGBA getValue(const std::string &varName, const NLMISC::CRGBA &defaultValue); + NLMISC::CRGBA getValue(const NLMISC::CConfigFile::CVar &var, const NLMISC::CRGBA &defaultValue); + + inline NLMISC::CConfigFile &getConfigFile() { return ConfigFile; } + +private: + static void cbConfigCallback(NLMISC::CConfigFile::CVar &var); + + void cfcbSearchPaths(NLMISC::CConfigFile::CVar &var); + + CConfiguration(const CConfiguration &); + CConfiguration &operator=(const CConfiguration &); + + NLMISC::CConfigFile ConfigFile; + std::map ConfigCallbacks; + +};/* class CConfiguration */ + +} /* namespace NLQT */ + +#endif // CONFIGURATION_H diff --git a/code/ryzom/tools/leveldesign/georges_editor_qt/src/entity.cpp b/code/ryzom/tools/leveldesign/georges_editor_qt/src/entity.cpp new file mode 100644 index 000000000..878b8e730 --- /dev/null +++ b/code/ryzom/tools/leveldesign/georges_editor_qt/src/entity.cpp @@ -0,0 +1,269 @@ +/* + Georges Editor Qt + Copyright (C) 2010 Adrian Jaekel + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . +*/ + +#include "entity.h" + +// NeL includes +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +// Project includes +#include "modules.h" + +using namespace NLMISC; +using namespace NL3D; + +namespace NLQT { + +CSlotInfo& CSlotInfo::operator=(const CSlotInfo & slotInfo) +{ + if ( this != &slotInfo) + { + Animation = slotInfo.Animation; + ClampMode = slotInfo.ClampMode; + Enable = slotInfo.Enable; + EndBlend = slotInfo.EndBlend; + EndTime = slotInfo.EndTime; + Offset = slotInfo.Offset; + Skeleton = slotInfo.Skeleton; + SkeletonInverted = slotInfo.SkeletonInverted; + Smoothness = slotInfo.Smoothness; + SpeedFactor = slotInfo.SpeedFactor; + StartBlend = slotInfo.StartBlend; + StartTime = slotInfo.StartTime; + } + return *this; +} + +CEntity::CEntity(void): + _Name(""), + _Instance(NULL), _Skeleton(NULL), + _PlayList(NULL), _AnimationSet(NULL) +{ +} + +CEntity::~CEntity(void) +{ +} + +void CEntity::loadAnimation(std::string &fileName) +{ + uint id = _AnimationSet->addAnimation(fileName.c_str(),CFile::getFilenameWithoutExtension(fileName).c_str()); + _AnimationList.push_back(_AnimationSet->getAnimationName(id)); + _AnimationSet->build(); + if (!_Skeleton.empty()) _PlayList->registerTransform(_Skeleton); + else _PlayList->registerTransform(_Instance); +} + +void CEntity::loadSWT(std::string &fileName) +{ + uint id = _AnimationSet->addSkeletonWeight(fileName.c_str(),CFile::getFilenameWithoutExtension(fileName).c_str()); + _SWTList.push_back(_AnimationSet->getSkeletonWeightName(id)); +} + +void CEntity::addAnimToPlayList(std::string &name) +{ + _PlayListAnimation.push_back(name); + + _AnimationStatus.EndAnim = this->getPlayListLength(); +} + +void CEntity::removeAnimToPlayList(uint row) +{ + if (row < _PlayListAnimation.size()) + _PlayListAnimation.erase(_PlayListAnimation.begin() + row); + + _AnimationStatus.EndAnim = this->getPlayListLength(); +} + +void CEntity::swapAnimToPlayList(uint row1, uint row2) +{ + if ((row1 < _PlayListAnimation.size()) && (row2 < _PlayListAnimation.size())) + std::swap(_PlayListAnimation[row1], _PlayListAnimation[row2]); +} + +void CEntity::playbackAnim(bool play) +{ + _AnimationStatus.PlayAnim = play; +} + +void CEntity::reset() +{ + _PlayListAnimation.clear(); + _AnimationList.clear(); + _SWTList.clear(); + + _PlayList->resetAllChannels(); +} + +float CEntity::getPlayListLength() +{ + // Accumul all the time + float time = 0; + for(size_t i = 0; i < _PlayListAnimation.size(); ++i) + time += getAnimLength(_PlayListAnimation[i]); + return time; +} + +float CEntity::getAnimLength(std::string name) +{ + uint id = _AnimationSet->getAnimationIdByName(name.c_str()); + NL3D::UAnimation *anim = _AnimationSet->getAnimation(id); + return anim->getEndTime() - anim->getBeginTime(); +} + +void CEntity::update(NL3D::TAnimationTime time) +{ + this->resetChannel(); + switch (_AnimationStatus.Mode) + { + case Mode::PlayList: + animatePlayList(time); + break; + case Mode::Mixer: + animateChannelMixer(); + break; + } +} + + +void CEntity::resetChannel() +{ + for(size_t i = 0; i < NL3D::CChannelMixer::NumAnimationSlot; i++) + _PlayList->setAnimation(i, UPlayList::empty); +} + +void CEntity::animatePlayList(NL3D::TAnimationTime time) +{ + if (!_PlayListAnimation.empty()) + { + // Animation index + uint id = _AnimationSet->getAnimationIdByName(_PlayListAnimation[0].c_str()); + + // Try channel AnimationSet + NL3D::UAnimation *anim = _AnimationSet->getAnimation(id); + + // Accumul time + float startTime = 0; + float endTime = anim->getEndTime() - anim->getBeginTime(); + + uint index = 0; + while (time >= endTime) + { + index++; + if (index < _PlayListAnimation.size()) + { + id = _AnimationSet->getAnimationIdByName(_PlayListAnimation[index].c_str()); + anim = _AnimationSet->getAnimation(id); + + // Add start time + startTime = endTime; + endTime = startTime + (anim->getEndTime() - anim->getBeginTime()); + } + else + break; + } + + // Time cropped ? + if (index >= _PlayListAnimation.size()) + { + // Yes + index--; + id = _AnimationSet->getAnimationIdByName(_PlayListAnimation[index].c_str()); + anim = _AnimationSet->getAnimation(id); + + // End time for last anim + startTime = anim->getEndTime() - time; + } + else + { + // No + id = _AnimationSet->getAnimationIdByName(_PlayListAnimation[index].c_str()); + anim = _AnimationSet->getAnimation(id); + + // Final time + startTime -= anim->getBeginTime(); + } + + // Set the slot + _PlayList->setAnimation(0, id); + _PlayList->setTimeOrigin(0, startTime); + _PlayList->setWeightSmoothness(0, 1.0f); + _PlayList->setStartWeight(0, 1, 0); + _PlayList->setEndWeight(0, 1, 1); + _PlayList->setWrapMode(0, UPlayList::Clamp); + } +} + +void CEntity::animateChannelMixer() +{ + for (uint i = 0; i < NL3D::CChannelMixer::NumAnimationSlot; i++) + { + if (_SlotInfo[i].Enable) + { + // Set the animation + uint animId = _AnimationSet->getAnimationIdByName(_SlotInfo[i].Animation); + if (animId == UAnimationSet::NotFound) + _PlayList->setAnimation(i, UPlayList::empty); + else + _PlayList->setAnimation(i, animId); + + // Set the skeleton weight + uint skelId = _AnimationSet->getSkeletonWeightIdByName(_SlotInfo[i].Skeleton); + if (skelId == UAnimationSet::NotFound) + _PlayList->setSkeletonWeight(i, UPlayList::empty, false); + else + _PlayList->setSkeletonWeight(i, skelId, _SlotInfo[i].SkeletonInverted); + + // Set others values + _PlayList->setTimeOrigin(i, _SlotInfo[i].Offset); + _PlayList->setSpeedFactor(i, _SlotInfo[i].SpeedFactor); + _PlayList->setStartWeight(i, _SlotInfo[i].StartBlend, _SlotInfo[i].StartTime); + _PlayList->setEndWeight(i, _SlotInfo[i].EndBlend, _SlotInfo[i].EndTime); + _PlayList->setWeightSmoothness(i, _SlotInfo[i].Smoothness); + + // Switch between wrap modes + switch (_SlotInfo[i].ClampMode) + { + case 0: + _PlayList->setWrapMode (i, UPlayList::Clamp); + break; + case 1: + _PlayList->setWrapMode (i, UPlayList::Repeat); + break; + case 2: + _PlayList->setWrapMode (i, UPlayList::Disable); + break; + } + } + } +} + +} /* namespace NLQT */ diff --git a/code/ryzom/tools/leveldesign/georges_editor_qt/src/entity.h b/code/ryzom/tools/leveldesign/georges_editor_qt/src/entity.h new file mode 100644 index 000000000..9ad938ec8 --- /dev/null +++ b/code/ryzom/tools/leveldesign/georges_editor_qt/src/entity.h @@ -0,0 +1,217 @@ +/* + Georges Editor Qt + Copyright (C) 2010 Adrian Jaekel + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . +*/ + +#ifndef ENTITY_H +#define ENTITY_H + +// STL includes +#include +#include +#include + +// NeL includes +#include "nel/3d/animation_time.h" +#include +#include +#include "nel/3d/channel_mixer.h" + +namespace NL3D { + class UPlayList; + class UAnimationSet; +} + +namespace NLQT { + +class CSlotInfo +{ +public: + CSlotInfo (): + Animation("empty"), Skeleton("empty"), + Offset(0), StartTime(0), EndTime(0), + StartBlend(1), EndBlend (1), Smoothness(1), + SpeedFactor(1), ClampMode(0), + SkeletonInverted(false), + Enable(true) {} ; + + std::string Animation; + std::string Skeleton; + float Offset; + float StartTime; + float EndTime; + + float StartBlend; + float EndBlend; + float Smoothness; + float SpeedFactor; + sint32 ClampMode; + bool SkeletonInverted; + bool Enable; + + CSlotInfo &operator=(const CSlotInfo &); +}; + + +/** +@class CEntity +Animated object. Allows you to upload animations for the shape. +Contains a built-in playlist. Has management and playback Playlists or Mixer. +*/ +class CEntity +{ +public: + struct Mode + { + enum List + { + PlayList = 1, + Mixer + }; + }; + + // will need for a single or multiple reproduction + struct SAnimationStatus + { + bool LoopAnim; + bool PlayAnim; + float CurrentTimeAnim; + float StartAnim; + float EndAnim; + float SpeedAnim; + int Mode; + + SAnimationStatus(): + LoopAnim(false), PlayAnim(false), + CurrentTimeAnim(0), StartAnim(0), + EndAnim(0), SpeedAnim(1), Mode(Mode::PlayList) {} + }; + + /// Constructor + CEntity(void); + + /// Destructor + ~CEntity(void); + + /// Loads a file animations + /// @param fileName - name animation file + void loadAnimation(std::string &fileName); + + /// Loads a file skeleton weight + void loadSWT(std::string &fileName); + + /// Adds an animation to a playlist + /// @param name - name loaded animations + void addAnimToPlayList(std::string &name); + + /// Removes the animation from a playlist + /// @param row - number of animations in the playlist + void removeAnimToPlayList(uint row); + + /// Swaps animations to a playlist + /// @param row1 - first number of animations in the playlist + /// @param row2 - second number of animations in the playlist + void swapAnimToPlayList(uint row1, uint row2); + + /// Playback animation + void playbackAnim(bool play); + + /// Reset playlist and animation + void reset(); + + /// Get the total time of animation playlist + /// @return total time of animation + float getPlayListLength(); + + /// get time length single animation + float getAnimLength(std::string name); + + /// Get slot infomation + void setSlotInfo(uint num, CSlotInfo& slotInfo) { _SlotInfo[num] = slotInfo; } + + /// Set use mode playlist or mixer + void setMode(int mode) { _AnimationStatus.Mode = mode; } + + /// Get information about the current status of playing a playlist + /// @return struct containing current information playback + SAnimationStatus& getStatus() { return _AnimationStatus; } + + /// Get name entity + /// @return name entity + std::string &getName() { return _Name; } + + /// Get slot information + CSlotInfo& getSlotInfo(uint num) { return _SlotInfo[num]; } + + /// Get list loaded animations files + std::vector& getAnimationList() { return _AnimationList; } + + /// Get playlist animations + std::vector& getPlayListAnimation() { return _PlayListAnimation; } + + /// Get list loaded skeleton weight template files + std::vector& getSWTList() { return _SWTList; } + +private: + + /// Update the animate from the playlist or channel mixer + /// @param time - current time in second + void update(NL3D::TAnimationTime time); + + void resetChannel(); + + /// Update the animate from the playlist + void animatePlayList(NL3D::TAnimationTime time); + + /// Update the animate from the mixer + void animateChannelMixer(); + + // The name of the entity + std::string _Name; + + SAnimationStatus _AnimationStatus; + + // The mesh instance associated to this entity + NL3D::UInstance _Instance; + + // The skeleton binded to the instance + NL3D::USkeleton _Skeleton; + + NL3D::UPlayList *_PlayList; + + NL3D::UAnimationSet *_AnimationSet; + + // Animation input file + std::vector _AnimationList; + + // Skeleton weight input file + std::vector _SWTList; + + // Play list animation + std::vector _PlayListAnimation; + + // Slot info for this object + CSlotInfo _SlotInfo[NL3D::CChannelMixer::NumAnimationSlot]; + + friend class CObjectViewer; +}; /* class CEntity */ + +typedef std::map CEntities; +typedef CEntities::iterator EIT; + +} /* namespace NLQT */ + +#endif // ENTITY_H diff --git a/code/ryzom/tools/leveldesign/georges_editor_qt/src/filesystem_model.cpp b/code/ryzom/tools/leveldesign/georges_editor_qt/src/filesystem_model.cpp new file mode 100644 index 000000000..3c52fcf78 --- /dev/null +++ b/code/ryzom/tools/leveldesign/georges_editor_qt/src/filesystem_model.cpp @@ -0,0 +1,70 @@ +/* + Georges Editor Qt + Copyright (C) 2010 Adrian Jaekel + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . +*/ + +#include "filesystem_model.h" + +#include +#include + +namespace NLQT { + + CFileSystemModel::CFileSystemModel(QString ldPath, QObject *parent) + : QFileSystemModel(parent), + _ldPath(ldPath){ + + } + CFileSystemModel::~CFileSystemModel() { + + } + + QVariant CFileSystemModel::data(const QModelIndex& index, int role) const { + + if (role == Qt::DecorationRole) { + if (_ldPath.isEmpty()) + return QVariant(); + if (isDir(index)) + return QApplication::style()->standardIcon(QStyle::SP_DirIcon); + } + if (_ldPath.isEmpty() && role == Qt::DisplayRole) { + if (index.parent().isValid()) + return QVariant(); + return QString("Set a correct leveldesign path ..."); + } + return QFileSystemModel::data(index, role); + } + + int CFileSystemModel::columnCount(const QModelIndex &/*parent*/) const + { + return 1; + } + + int CFileSystemModel::rowCount(const QModelIndex &parent) const + { + if (_ldPath.isEmpty()) { + if(parent.isValid()) { + return 0; + } else { + return qMin(QFileSystemModel::rowCount(parent),1); + } + } + return QFileSystemModel::rowCount(parent); + } + +} /* namespace NLQT */ + +/* end of file */ diff --git a/code/ryzom/tools/leveldesign/georges_editor_qt/src/filesystem_model.h b/code/ryzom/tools/leveldesign/georges_editor_qt/src/filesystem_model.h new file mode 100644 index 000000000..7e5ccdbd3 --- /dev/null +++ b/code/ryzom/tools/leveldesign/georges_editor_qt/src/filesystem_model.h @@ -0,0 +1,43 @@ +/* + Georges Editor Qt + Copyright (C) 2010 Adrian Jaekel + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . +*/ + +#ifndef FILESYSTEM_MODEL_H +#define FILESYSTEM_MODEL_H + +#include + +namespace NLQT { + + class CFileSystemModel : public QFileSystemModel + { + QString _ldPath; + + public: + CFileSystemModel(QString ldPath, QObject *parent = 0); + ~CFileSystemModel(); + + int columnCount(const QModelIndex &/*parent*/) const; + int rowCount(const QModelIndex &/*parent*/) const; + + QVariant data(const QModelIndex& index, int role) const ; + + };/* class CFileSystemModel */ + +} /* namespace NLQT */ + +#endif // FILESYSTEM_MODEL_H \ No newline at end of file diff --git a/code/ryzom/tools/leveldesign/georges_editor_qt/src/formitem.cpp b/code/ryzom/tools/leveldesign/georges_editor_qt/src/formitem.cpp new file mode 100644 index 000000000..aa2f4ce7c --- /dev/null +++ b/code/ryzom/tools/leveldesign/georges_editor_qt/src/formitem.cpp @@ -0,0 +1,103 @@ +/* +Georges Editor Qt +Copyright (C) 2010 Adrian Jaekel + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program. If not, see . +*/ + +#include "formitem.h" + +// Qt includes + + +// NeL includes +#include + +namespace NLQT { + + CFormItem::CFormItem(NLGEORGES::UFormElm* elm, const QList &data, CFormItem *parent, + NLGEORGES::UFormElm::TWhereIsValue wV, NLGEORGES::UFormElm::TWhereIsNode wN) { + parentItem = parent; + itemData = data; + formElm = elm; + whereV = wV; + whereN = wN; + } + + CFormItem::~CFormItem() { + qDeleteAll(childItems); + } + + void CFormItem::appendChild(CFormItem *item) { + childItems.append(item); + } + + CFormItem *CFormItem::child(int row) { + return childItems.value(row); + } + + int CFormItem::childCount() const { + return childItems.count(); + } + + int CFormItem::columnCount() const { + return itemData.count(); + } + + QVariant CFormItem::data(int column) const { + return itemData.value(column); + } + + CFormItem *CFormItem::parent() + { + return parentItem; + } + + int CFormItem::row() const { + if (parentItem) + return parentItem->childItems.indexOf(const_cast(this)); + + return 0; + } + + bool CFormItem::setData(int column, const QVariant &value) { + if (column < 0 || column >= itemData.size()) + return false; + + itemData[column] = value; + if (formElm->isAtom()) { + const NLGEORGES::UType *type = formElm->getType(); + if (type) { + switch (type->getType()) { + case NLGEORGES::UType::UnsignedInt: + case NLGEORGES::UType::SignedInt: + case NLGEORGES::UType::Double: + case NLGEORGES::UType::String: + nldebug(QString("string %1 %2") + .arg(itemData[0].toString()).arg(value.toString()) + .toStdString().c_str()); + parentItem->formElm->setValueByName( + value.toString().toStdString().c_str(),itemData[0].toString().toStdString().c_str()); + break; + case NLGEORGES::UType::Color: + break; + default: + break; + } + } + } + //formElm->setValueByName(); + return true; + } +} diff --git a/code/ryzom/tools/leveldesign/georges_editor_qt/src/formitem.h b/code/ryzom/tools/leveldesign/georges_editor_qt/src/formitem.h new file mode 100644 index 000000000..c10d39c84 --- /dev/null +++ b/code/ryzom/tools/leveldesign/georges_editor_qt/src/formitem.h @@ -0,0 +1,68 @@ +/* + Georges Editor Qt + Copyright (C) 2010 Adrian Jaekel + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . +*/ + +#ifndef FORMITEM_H +#define FORMITEM_H + +// NeL includes +#include + +// Qt includes +#include +#include + +namespace NLQT { + + class CFormItem + + { + public: + CFormItem(NLGEORGES::UFormElm *elm, const QList &data, + CFormItem *parent = 0, + NLGEORGES::UFormElm::TWhereIsValue = NLGEORGES::UFormElm::ValueForm, + NLGEORGES::UFormElm::TWhereIsNode = NLGEORGES::UFormElm::NodeForm); + ~CFormItem(); + + void appendChild(CFormItem *child); + + CFormItem *child(int row); + int childCount() const; + int columnCount() const; + QVariant data(int column) const; + int row() const; + CFormItem *parent(); + bool setData(int column, const QVariant &value); + NLGEORGES::UFormElm* getFormElm() {return formElm;}; + NLGEORGES::UFormElm::TWhereIsValue CFormItem::valueFrom() { + return whereV; + } + NLGEORGES::UFormElm::TWhereIsNode CFormItem::nodeFrom() { + return whereN; + } + + private: + QList childItems; + QList itemData; + CFormItem *parentItem; + NLGEORGES::UFormElm* formElm; + NLGEORGES::UFormElm::TWhereIsValue whereV; + NLGEORGES::UFormElm::TWhereIsNode whereN; + }; // CFormItem + +} + #endif // FORMITEM_H \ No newline at end of file diff --git a/code/ryzom/tools/leveldesign/georges_editor_qt/src/georges.cpp b/code/ryzom/tools/leveldesign/georges_editor_qt/src/georges.cpp new file mode 100644 index 000000000..aea247813 --- /dev/null +++ b/code/ryzom/tools/leveldesign/georges_editor_qt/src/georges.cpp @@ -0,0 +1,46 @@ +/* +Georges Editor Qt +Copyright (C) 2010 Adrian Jaekel + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program. If not, see . +*/ + +#include "georges.h" +#include "nel/misc/o_xml.h" + +// STL includes + +// NeL includes +#include +#include + +// Project includes + +using namespace NLGEORGES; + +namespace NLQT { + + CGeorges::CGeorges(): FormLoader(0) { + FormLoader = UFormLoader::createLoader(); + } + + CGeorges::~CGeorges() {} + + UForm *CGeorges::loadForm(std::string formName) { + UForm *form = FormLoader->loadForm(formName.c_str()); + + return form; + } + +} /* namespace NLQT */ diff --git a/code/ryzom/tools/leveldesign/georges_editor_qt/src/georges.h b/code/ryzom/tools/leveldesign/georges_editor_qt/src/georges.h new file mode 100644 index 000000000..aa1aac4f0 --- /dev/null +++ b/code/ryzom/tools/leveldesign/georges_editor_qt/src/georges.h @@ -0,0 +1,64 @@ +/* + Georges Editor Qt + Copyright (C) 2010 Adrian Jaekel + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . +*/ + +#ifndef GEORGES_H +#define GEORGES_H + +// Misc + +// STL includes +#include + +// NeL includes + +// Qt includes + +// Project includes + +namespace NLGEORGES +{ + class UForm; + class UFormLoader; +} + +using namespace NLGEORGES; + +namespace NLQT { + +/** +@class CGeorges +A CGeorges class loading and viewing sheets. +*/ +class CGeorges +{ +public: + /// Default constructor. + CGeorges(); + virtual ~CGeorges(); + + // Load the given form root + UForm* loadForm(std::string formName); + + // A form loader + UFormLoader *FormLoader; + +};/* class CGeorges */ + +} /* namespace NLQT */ + +#endif // GEORGES_H diff --git a/code/ryzom/tools/leveldesign/georges_editor_qt/src/georges_dirtree_dialog.cpp b/code/ryzom/tools/leveldesign/georges_editor_qt/src/georges_dirtree_dialog.cpp new file mode 100644 index 000000000..a0f150f87 --- /dev/null +++ b/code/ryzom/tools/leveldesign/georges_editor_qt/src/georges_dirtree_dialog.cpp @@ -0,0 +1,130 @@ +/* +Georges Editor Qt +Copyright (C) 2010 Adrian Jaekel + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program. If not, see . + +*/ + +#include "georges_dirtree_dialog.h" + +// Qt includes +#include +#include + +// NeL includes + +// Project includes +#include "modules.h" + +using namespace NLMISC; + +namespace NLQT { + + CGeorgesDirTreeDialog::CGeorgesDirTreeDialog(QString ldPath, QWidget *parent): + QDockWidget(parent), + _ldPath(ldPath){ + + _ui.setupUi(this); + + //QStyleOptionViewItem myButtonOption; + // const QStyleOptionViewItem *buttonOption = + // qstyleoption_cast(_ui.dirTree->style()); + + /*setStyleSheet(" \ + QTreeView { \ + alternate-background-color: yellow; \ + } \ + QTreeView::item { \ + border: 1px solid #d9d9d9; \ + border-top-color: transparent; \ + border-bottom-color: transparent; \ + } \ + QTreeView::item:hover { \ + background: qlineargradient(x1: 0, y1: 0, x2: 0, y2: 1, stop: 0 #e7effd, stop: 1 #cbdaf1);\ + border: 1px solid #bfcde4; \ + } \ + QTreeView::item:selected { \ + border: 1px solid #567dbc; \ + } \ + QTreeView::item:selected:active{ \ + background: qlineargradient(x1: 0, y1: 0, x2: 0, y2: 1, stop: 0 #6ea1f1, stop: 1 #567dbc);\ + } \ + QTreeView::item:selected:!active { \ + background: qlineargradient(x1: 0, y1: 0, x2: 0, y2: 1, stop: 0 #6b9be8, stop: 1 #577fbf);\ + }\ + ");*/ + //QString leveldata = Modules::config().getConfigFile().getVar("SearchPaths").asString().c_str(); + + _dirModel = new CFileSystemModel(_ldPath); + _ui.dirTree->setModel(_dirModel); + + QFileInfo info(_ldPath); + + if (!_ldPath.isEmpty() && info.isDir()) { + _dirModel->setRootPath(_ldPath); + _ui.dirTree->setRootIndex(_dirModel->index(_ldPath)); + } else { + _dirModel->setRootPath(QDir::currentPath()); + } + + _ui.dirTree->setAnimated(false); + _ui.dirTree->setIndentation(20); + //_ui.dirTree->setSortingEnabled(true); + + /*connect(_ui.dirTree, SIGNAL(clicked(QModelIndex)), + this, SLOT(fileSelected(QModelIndex)));*/ + connect(_ui.dirTree, SIGNAL(activated(QModelIndex)), + this, SLOT(fileSelected(QModelIndex))); +} + +CGeorgesDirTreeDialog::~CGeorgesDirTreeDialog() { + delete _dirModel; +} + +void CGeorgesDirTreeDialog::fileSelected(QModelIndex index) { + QString name; + if (index.isValid() && !_dirModel->isDir(index)) { + Q_EMIT selectedForm(_dirModel->fileName(index)); + } +} + +void CGeorgesDirTreeDialog::changeFile(QString file) { + QModelIndex index = _dirModel->index(file); + //_dirModel->; + _ui.dirTree->selectionModel()->select(index,QItemSelectionModel::ClearAndSelect); + _ui.dirTree->scrollTo(index,QAbstractItemView::PositionAtCenter); + fileSelected(index); +} + +void CGeorgesDirTreeDialog::ldPathChanged(QString path) { + _ldPath = path; + QFileInfo info(_ldPath); + + delete _dirModel; + + if (!_ldPath.isEmpty() && info.isDir()) { + _dirModel = new CFileSystemModel(_ldPath); + _ui.dirTree->setModel(_dirModel); + _dirModel->setRootPath(_ldPath); + _ui.dirTree->setRootIndex(_dirModel->index(_ldPath)); + } else { + _dirModel = new CFileSystemModel(""); + _ui.dirTree->setModel(_dirModel); + _dirModel->setRootPath(QDir::currentPath()); + _ldPath = ""; + } +} + +} /* namespace NLQT */ \ No newline at end of file diff --git a/code/ryzom/tools/leveldesign/georges_editor_qt/src/georges_dirtree_dialog.h b/code/ryzom/tools/leveldesign/georges_editor_qt/src/georges_dirtree_dialog.h new file mode 100644 index 000000000..c8a104dc6 --- /dev/null +++ b/code/ryzom/tools/leveldesign/georges_editor_qt/src/georges_dirtree_dialog.h @@ -0,0 +1,64 @@ +/* + Georges Editor Qt + Copyright (C) 2010 Adrian Jaekel + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . +*/ + +#ifndef GEORGES_DIRTREE_DIALOG_H +#define GEORGES_DIRTREE_DIALOG_H + +// Qt includes +#include + +// STL includes + +// NeL includes + +// Project includes +#include "ui_georges_dirtree_form.h" +#include "filesystem_model.h" + +namespace NLQT { + +class CGeorgesDirTreeDialog: public QDockWidget +{ + Q_OBJECT + +public: + CGeorgesDirTreeDialog(QString ldPath, QWidget *parent = 0); + ~CGeorgesDirTreeDialog(); + +private: + Ui::CGeorgesDirTreeDialog _ui; + + CFileSystemModel *_dirModel; + QString _ldPath; + +Q_SIGNALS: + void selectedForm(QString); + +public Q_SLOTS: + void ldPathChanged(QString path); + +private Q_SLOTS: + void fileSelected(QModelIndex index); + void changeFile(QString file); + + friend class CMainWindow; +}; /* CGEorgesDirTreeDialog */ + +} /* namespace NLQT */ + +#endif // GEORGES_DIRTREE_DIALOG_H diff --git a/code/ryzom/tools/leveldesign/georges_editor_qt/src/georges_dirtree_form.ui b/code/ryzom/tools/leveldesign/georges_editor_qt/src/georges_dirtree_form.ui new file mode 100644 index 000000000..52296e1fa --- /dev/null +++ b/code/ryzom/tools/leveldesign/georges_editor_qt/src/georges_dirtree_form.ui @@ -0,0 +1,51 @@ + + + CGeorgesDirTreeDialog + + + + 0 + 0 + 400 + 300 + + + + + 0 + 0 + + + + + 200 + 111 + + + + Dir Tree + + + + + 50 + 0 + + + + + + + + 0 + 0 + + + + + + + + + + diff --git a/code/ryzom/tools/leveldesign/georges_editor_qt/src/georges_editor_qt.qrc b/code/ryzom/tools/leveldesign/georges_editor_qt/src/georges_editor_qt.qrc new file mode 100644 index 000000000..58efbb3a0 --- /dev/null +++ b/code/ryzom/tools/leveldesign/georges_editor_qt/src/georges_editor_qt.qrc @@ -0,0 +1,13 @@ + + + images/nel.png + images/open-file.png + images/go-down.png + images/go-up.png + images/list-add.png + images/list-remove.png + images/preferences.png + images/pqrticles.png + images/khead.png + + diff --git a/code/ryzom/tools/leveldesign/georges_editor_qt/src/georges_treeview_dialog.cpp b/code/ryzom/tools/leveldesign/georges_editor_qt/src/georges_treeview_dialog.cpp new file mode 100644 index 000000000..ff0dd4ac4 --- /dev/null +++ b/code/ryzom/tools/leveldesign/georges_editor_qt/src/georges_treeview_dialog.cpp @@ -0,0 +1,271 @@ +/* +Georges Editor Qt +Copyright (C) 2010 Adrian Jaekel + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program. If not, see . + +*/ + +#include "georges_treeview_dialog.h" + +// Qt includes +#include +#include + +// NeL includes +#include +#include +#include +#include + +// Project includes +#include "modules.h" +#include "georgesform_model.h" +#include "georgesform_proxy_model.h" +#include "formitem.h" +#include "spindelegate.h" + +using namespace NLMISC; +using namespace NLGEORGES; + +namespace NLQT { + + CGeorgesTreeViewDialog::CGeorgesTreeViewDialog(QWidget *parent /*= 0*/, bool emptyView /*= false*/) + : QDockWidget(parent) + { + loadedForm = ""; + _modified = false; + + _ui.setupUi(this); + _ui.treeViewTabWidget->setTabEnabled (2,false); + + if (emptyView) { + _ui.treeViewTabWidget->clear(); + setWindowTitle("Form Area"); + } + + _ui.checkBoxParent->setStyleSheet("background-color: rgba(0,255,0,30)"); + _ui.checkBoxDefaults->setStyleSheet("background-color: rgba(255,0,0,30)"); + _form = 0; + + SpinBoxDelegate *spindelegate = new SpinBoxDelegate(this); + _ui.treeView->setItemDelegateForColumn(1, spindelegate); + + + connect(_ui.treeView, SIGNAL(doubleClicked (QModelIndex)), + this, SLOT(doubleClicked (QModelIndex))); + connect(_ui.checkBoxParent, SIGNAL(stateChanged(int)), + this, SLOT(showParentRows (int))); + } + + CGeorgesTreeViewDialog::~CGeorgesTreeViewDialog() + { + delete _ui.treeView->itemDelegateForColumn(1); + deleteLater(); + //QSettings settings("RyzomCore", "GeorgesQt"); + //settings.setValue("dirViewGeometry", saveGeometry()); + } + + void CGeorgesTreeViewDialog::selectedForm(QString formName) { + _form = Modules::georges().loadForm(formName.toStdString()); + + if (_form) { + UFormElm *root = 0; + root = &_form->getRootNode(); + + QStringList parents; + for (uint i = 0; i < _form->getNumParent(); i++) { + UForm *u = _form->getParentForm(i); + parents << u->getFilename().c_str(); + } + + QString comments; + comments = _form->getComment().c_str(); + + if (!comments.isEmpty()) { + _ui.treeViewTabWidget->setTabEnabled (1,true); + _ui.commentEdit->setPlainText(comments); + } + + QStringList strList; + std::set dependencies; + _form->getDependencies(dependencies); + + QMap< QString, QStringList> deps; + Q_FOREACH(std::string str, dependencies) { + QString file = str.c_str(); + if (file == formName) continue; + deps[file.remove(0,file.indexOf(".")+1)] << str.c_str(); + } + nlinfo("typ's %d",deps["typ"].count()); + nlinfo("dfn's %d",deps["dfn"].count()); + + //nlwarning(strList.join(";").toStdString().c_str()); + if (root) { + loadedForm = formName; + + CGeorgesFormModel *model = new CGeorgesFormModel(root,deps,comments,parents); + CGeorgesFormProxyModel *proxyModel = new CGeorgesFormProxyModel(); + proxyModel->setSourceModel(model); + _ui.treeView->setModel(proxyModel); + _ui.treeView->expandAll(); + _ui.treeView->resizeColumnToContents(0); + _ui.treeView->resizeColumnToContents(1); + _ui.treeView->resizeColumnToContents(2); + _ui.treeView->hideColumn(3); + + showParentRows(_ui.checkBoxParent->isChecked()); + + //_ui.treeView->setRowHidden(0,QModelIndex(),true); + connect(model, SIGNAL(dataChanged(const QModelIndex, const QModelIndex)), + this, SLOT(modifiedFile())); + + Modules::mainWin().setWindowTitle("Qt Georges Editor - " + formName); + //Modules::mainWin().getTabBar(); + } + } + } + + void CGeorgesTreeViewDialog::modifiedFile( ) { + if (!_modified) { + _modified = true; + setWindowTitle(windowTitle()+"*"); + Modules::mainWin().setWindowTitle(Modules::mainWin().windowTitle()+"*"); + Q_EMIT modified(_modified); + } + } + + void CGeorgesTreeViewDialog::write( ) { + + COFile file; + std::string s = CPath::lookup(loadedForm.toStdString()); + if (file.open (s)) { + try { + if (loadedForm.contains(".typ")) { + //nlassert (Type != NULL); + + //// Write the file + //// Modified ? + //if (IsModified ()) + //{ + // Type->Header.MinorVersion++; + // flushValueChange (); + //} + //Type->write (xmlStream.getDocument (), theApp.Georges4CVS); + //modify (NULL, NULL, false); + //flushValueChange (); + //UpdateAllViews (NULL); + //return TRUE; + } else if (loadedForm.contains(".dfn")) { + //nlassert (Dfn != NULL); + + //// Write the file + //if (IsModified ()) + //{ + // Dfn->Header.MinorVersion++; + // flushValueChange (); + //} + //Dfn->write (xmlStream.getDocument (), lpszPathName, theApp.Georges4CVS); + //modify (NULL, NULL, false); + //UpdateAllViews (NULL); + //return TRUE; + } else { + nlassert (_form != NULL); + + // Write the file + /*if (IsModified ()) + { + ((CForm*)(UForm*)Form)->Header.MinorVersion++; + }*/ + //((CForm*)(UForm*)Form)->write (xmlStream.getDocument (), lpszPathName, theApp.Georges4CVS); + _form->write(file, false); + setWindowTitle(windowTitle().remove("*")); + _modified = false; + //if (strcmp (xmlStream.getErrorString (), "") != 0) + //{ + // char message[512]; + // smprintf (message, 512, "Error while saving file: %s", xmlStream.getErrorString ()); + //theApp.outputError (message); + //} + //modify (NULL, NULL, false); + //flushValueChange (); + //UpdateAllViews (NULL); + + // Get the left view + //CView* pView = getLeftView (); + } + } catch (Exception &e) { + nlerror("Error while loading file: %s", e.what()); + } + } else { //if (!file.open()) + nlerror("Can't open the file %s for writing.", s); + } + } + + void CGeorgesTreeViewDialog::doubleClicked ( const QModelIndex & index ) { + if (index.column() == 1) return; + CFormItem *item = static_cast(index.internalPointer()); + + QString value = item->data(1).toString(); + QString path = CPath::lookup(value.toStdString(),false).c_str(); + + if (!path.isEmpty() && !path.contains(".shape")) + Q_EMIT changeFile(path); + if (path.contains(".shape")) { + Modules::objView().resetScene(); + Modules::config().configRemapExtensions(); + Modules::objView().loadMesh(path.toStdString(),""); + } + int i = 0; + } + + void CGeorgesTreeViewDialog::closeEvent(QCloseEvent *event) { + if (Modules::mainWin().getEmptyView() == this) { + event->ignore(); + } else { + Modules::mainWin().getTreeViewList().removeOne(this); + if(!Modules::mainWin().getTreeViewList().size()) { + Modules::mainWin().createEmptyView(); + } + deleteLater(); + } + } + + void CGeorgesTreeViewDialog::showParentRows(int newState) { + CGeorgesFormProxyModel * mp = dynamic_cast(_ui.treeView->model()); + CGeorgesFormModel *m = qobject_cast(mp->sourceModel()); + + for (int i = 0; i < m->rowCount(); i++) { + const QModelIndex in = m->index(i,0); + if (m->getItem(in)->nodeFrom() == UFormElm::NodeParentForm) { + if (newState == Qt::Checked) { + _ui.treeView->setRowHidden(in.row(),in.parent(),false); + } else { + _ui.treeView->setRowHidden(in.row(),in.parent(),true); + } + } else { // search childs // recursive? + for (int j = 0; j < m->rowCount(in); j++) { + const QModelIndex in2 = m->index(j,0,in); + if (m->getItem(in2)->nodeFrom() == UFormElm::NodeParentForm) { + if (newState == Qt::Checked) { + _ui.treeView->setRowHidden(in2.row(),in,false); + } else { + _ui.treeView->setRowHidden(in2.row(),in,true); + } + } + } + } // end of search childs + } + } +} /* namespace NLQT */ \ No newline at end of file diff --git a/code/ryzom/tools/leveldesign/georges_editor_qt/src/georges_treeview_dialog.h b/code/ryzom/tools/leveldesign/georges_editor_qt/src/georges_treeview_dialog.h new file mode 100644 index 000000000..d40d2b870 --- /dev/null +++ b/code/ryzom/tools/leveldesign/georges_editor_qt/src/georges_treeview_dialog.h @@ -0,0 +1,80 @@ +/* +Georges Editor Qt +Copyright (C) 2010 Adrian Jaekel + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program. If not, see . +*/ + +#ifndef GEORGES_TREEVIEWER_DIALOG_H +#define GEORGES_TREEVIEWER_DIALOG_H + +#include "ui_georges_treeview_form.h" + +// Qt includes +#include + +// STL includes + +// NeL includes + +// Project includes + +namespace NLGEORGES +{ + class UForm; +} + +using namespace NLGEORGES; + +namespace NLQT { + + class CGeorgesTreeViewDialog: public QDockWidget + { + Q_OBJECT + + public: + CGeorgesTreeViewDialog(QWidget *parent = 0, bool empty = false); + ~CGeorgesTreeViewDialog(); + + bool modified() {return _modified;} + void setModified(bool m) {_modified = m;} + + void write ( ); + + QString loadedForm; + + protected: + void closeEvent(QCloseEvent *event); + + Q_SIGNALS: + void changeFile(QString); + void modified(bool); + public Q_SLOTS: + void selectedForm(QString); + private Q_SLOTS: + void doubleClicked ( const QModelIndex & index ); + void modifiedFile( ); + void showParentRows(int); + + private: + Ui::CGeorgesTreeViewDialog _ui; + UForm *_form; + + bool _modified; + + }; /* CGeorgesTreeViewDialog */ + +} /* namespace NLQT */ + +#endif // GEORGES_TREEVIEWER_DIALOG_H diff --git a/code/ryzom/tools/leveldesign/georges_editor_qt/src/georges_treeview_form.ui b/code/ryzom/tools/leveldesign/georges_editor_qt/src/georges_treeview_form.ui new file mode 100644 index 000000000..873747794 --- /dev/null +++ b/code/ryzom/tools/leveldesign/georges_editor_qt/src/georges_treeview_form.ui @@ -0,0 +1,122 @@ + + + CGeorgesTreeViewDialog + + + + 0 + 0 + 400 + 300 + + + + + 0 + 0 + + + + + 241 + 236 + + + + + + + + + + + QTabWidget::West + + + 0 + + + + Form + + + + 0 + + + + + + 0 + 0 + + + + + 0 + 0 + + + + + + + + Parent + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + Defaults + + + + + + + + Comment + + + + + + false + + + + + + + + Log + + + + + + + + + + + + + + + diff --git a/code/ryzom/tools/leveldesign/georges_editor_qt/src/georgesform_model.cpp b/code/ryzom/tools/leveldesign/georges_editor_qt/src/georgesform_model.cpp new file mode 100644 index 000000000..43fa322c0 --- /dev/null +++ b/code/ryzom/tools/leveldesign/georges_editor_qt/src/georgesform_model.cpp @@ -0,0 +1,442 @@ +/* + Georges Editor Qt + Copyright (C) 2010 Adrian Jaekel + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . +*/ + +#include "georgesform_model.h" + +// NeL includes +#include +#include +#include +#include +#include +#include + +// Qt includes +#include +#include +#include +#include +#include + +// project includes +#include "formitem.h" + +using namespace NLGEORGES; + +namespace NLQT { + + CGeorgesFormModel::CGeorgesFormModel(UFormElm *rootElm, QMap< QString, QStringList> deps, + QString comment, QStringList parents, QObject *parent) : QAbstractItemModel(parent) { + + QList rootData; + rootData << "Value" << "Data" << "Extra" << "Type"; + _rootElm = rootElm; + _rootItem = new CFormItem(_rootElm, rootData); + _dependencies = deps; + _comments = comment; + _parents = parents; + _parentRows = new QList; + + setupModelData(); + } + + CGeorgesFormModel::~CGeorgesFormModel() { + delete _rootItem; + } + + /******************************************************************************/ + + QVariant CGeorgesFormModel::data(const QModelIndex &p_index, int p_role) const { + + if (!p_index.isValid()) + return QVariant(); + + switch (p_role) { + case Qt::DisplayRole: + { + return getItem(p_index)->data(p_index.column()); + } + case Qt::BackgroundRole: + { + if (getItem(p_index)->valueFrom() == UFormElm::ValueDefaultDfn) + return QBrush(QColor(255,0,0,30)); + if (getItem(p_index)->nodeFrom() == UFormElm::NodeParentForm) + return QBrush(QColor(0,255,0,30)); + return QVariant(); + } + case Qt::DecorationRole: + { + if (p_index.column() == 2) { + //p_index. + QModelIndex in = index(p_index.row(),p_index.column()-1,p_index.parent()); + CFormItem *item = getItem(in); + + QString value = item->data(1).toString(); + //QString path = NLMISC::CPath::lookup(value.toStdString(),false).c_str(); + + if (value.contains(".shape")) { + return QIcon(":/images/pqrticles.png"); + } else if(value.contains(".tga") || value.contains(".png")) { + qDebug() << p_index << p_role; + QString path = NLMISC::CPath::lookup(value.toStdString(),false).c_str(); + return QIcon(":/images/pqrticles.png"); + } + } + return QVariant(); + break; + } + default: + return QVariant(); + } + } + + /******************************************************************************/ + + CFormItem *CGeorgesFormModel::getItem(const QModelIndex &index) const { + if (index.isValid()) { + CFormItem *item = static_cast(index.internalPointer()); + if (item) return item; + } + return _rootItem; + } + + /******************************************************************************/ + + bool CGeorgesFormModel::setData(const QModelIndex &index, const QVariant &value, + int role) { + + if (role != Qt::EditRole) + return false; + + CFormItem *item = getItem(index); + bool result = item->setData(index.column(), value); + + if (result) + Q_EMIT dataChanged(index, index); + + return result; + } + + /******************************************************************************/ + + Qt::ItemFlags CGeorgesFormModel::flags(const QModelIndex& index) const { + + if (!index.isValid()) + return 0; + + Qt::ItemFlags returnValue = Qt::ItemIsSelectable | Qt::ItemIsEnabled; + + if(index.column() == 1) + returnValue |= Qt::ItemIsEditable; + + return returnValue; + + } + + /******************************************************************************/ + + QVariant CGeorgesFormModel::headerData(int section, + Qt::Orientation orientation, int role) const + { + if (orientation == Qt::Horizontal && role == Qt::DisplayRole) + return _rootItem->data(section); + + return QVariant(); + + } + + /******************************************************************************/ + + QModelIndex CGeorgesFormModel::index(int row, int column, const QModelIndex &parent) + const + { + if (!hasIndex(row, column, parent)) + return QModelIndex(); + + CFormItem *parentItem; + + if (!parent.isValid()) + parentItem = _rootItem; + else + parentItem = static_cast(parent.internalPointer()); + + CFormItem *childItem = parentItem->child(row); + if (childItem) + return createIndex(row, column, childItem); + else + return QModelIndex(); + } + + /******************************************************************************/ + + QModelIndex CGeorgesFormModel::parent(const QModelIndex &index) const + { + if (!index.isValid()) + return QModelIndex(); + + CFormItem *childItem = static_cast(index.internalPointer()); + CFormItem *parentItem = childItem->parent(); + + if (parentItem == _rootItem) + return QModelIndex(); + + return createIndex(parentItem->row(), 0, parentItem); + } + + /******************************************************************************/ + + int CGeorgesFormModel::rowCount(const QModelIndex &parent) const { + + CFormItem *parentItem; + if (parent.column() > 0) + return 0; + + if (!parent.isValid()) + parentItem = _rootItem; + else + parentItem = static_cast(parent.internalPointer()); + + return parentItem->childCount(); + + } + + /******************************************************************************/ + + int CGeorgesFormModel::columnCount(const QModelIndex &parent) const { + + if (parent.isValid()) + return static_cast(parent.internalPointer())->columnCount(); + else + return _rootItem->columnCount(); + + } + + /******************************************************************************/ + + void CGeorgesFormModel::loadFormData(UFormElm *root, CFormItem *parent) { + + if (!root) return; + + uint num = 0; + UFormElm::TWhereIsNode *whereN = new UFormElm::TWhereIsNode; + UFormElm::TWhereIsValue *whereV = new UFormElm::TWhereIsValue; + + if (root->isStruct()) { + //((CFormElm*)root)->getForm()->getComment(); + uint structSize = 0; + root->getStructSize(structSize); + while (num < structSize) { + // Append a new item to the current parent's list of children. + std::string elmName; + if(root->getStructNodeName(num, elmName)) { + QList columnData; + //QVariant value; + std::string value; + //NLMISC::CRGBA value_color; + //uint value_uint; + //sint value_sint; + //double value_double; + QString elmtType = ""; + UFormElm *elmt = 0; + if(root->getNodeByName(&elmt, elmName.c_str(), whereN, true)) { + if (elmt) { + if (elmt->isArray()) + elmtType = "Array"; + if (elmt->isStruct()) + elmtType = "Struct"; + if (elmt->isAtom()) { + elmtType = "Atom"; + uint numDefinitions = 0; + const UType *type = elmt->getType(); + if (type) { + numDefinitions = type->getNumDefinition(); + root->getValueByName(value, elmName.c_str(),UFormElm::Eval,whereV); + switch (type->getType()) { + case UType::UnsignedInt: + value = QString("%1").arg(QString("%1").arg(value.c_str()).toDouble()).toStdString(); + elmtType.append("_uint");break; + case UType::SignedInt: + value = QString("%1").arg(QString("%1").arg(value.c_str()).toDouble()).toStdString(); + elmtType.append("_sint");break; + case UType::Double: + value = QString("%1").arg(QString("%1").arg(value.c_str()).toDouble(),0,'f',1).toStdString(); + elmtType.append("_double");break; + case UType::String: + elmtType.append("_string");break; + case UType::Color: + elmtType.append("_color");break; + default: + elmtType.append("_unknownType"); + } + } + + if (numDefinitions) { + std::string l, v; + QString tmpLabel, tmpValue; + for (uint i = 0; i < numDefinitions; i++) { + type->getDefinition(i,l,v); + tmpLabel = l.c_str(); + tmpValue = v.c_str(); + if (type->getType() == UType::SignedInt) { + if (QString("%1").arg(value.c_str()).toDouble() == tmpValue.toDouble()) { + value = l; + break; + } + } + if (type->getType() == UType::String) { + if (QString(value.c_str()) == tmpValue) { + value = l; + break; + } + } + } + } + } + if (elmt->isVirtualStruct()){ + root->getValueByName(value, elmName.c_str(),UFormElm::Eval,whereV); + elmtType = "VirtualStruct"; + } + switch (*whereN) { + case UFormElm::NodeForm: + elmtType.append("_fromForm"); break; + case UFormElm::NodeParentForm: + elmtType.append("_fromParentForm"); break; + case UFormElm::NodeDfn: + elmtType.append("_isDFN"); break; + case UFormElm::NodeType: + elmtType.append("_isType"); break; + default: + elmtType.append("_noNode"); + } + switch (*whereV) { + case UFormElm::ValueForm: + elmtType.append("_formValue"); break; + case UFormElm::ValueParentForm: + elmtType.append("_parentValue"); break; + case UFormElm::ValueDefaultDfn: + elmtType.append("_dfnValue"); break; + case UFormElm::ValueDefaultType: + elmtType.append("_typeValue"); break; + default: + elmtType.append("_noValue"); + } + columnData << QString(elmName.c_str()) << QString(value.c_str()) << "" << elmtType; + parent->appendChild(new CFormItem(elmt, columnData, parent, *whereV, *whereN)); + //if (parents.last()->childCount() > 0) { + // parents << parents.last()->child(parents.last()->childCount()-1); + //} + loadFormData(elmt, parent->child(parent->childCount()-1)); + } else { + // add Defaults + //columnData << QString(elmName.c_str()) << QString("default") << QString("default"); + //parent->appendChild(new CFormItem(elmt, columnData, parent, UFormElm::ValueDefaultDfn, UFormElm::NodeDfn)); + } + } + } + + num++; + } + } + if (root->isArray()) { + uint arraySize = 0; + root->getArraySize(arraySize); + while (num < arraySize) { + std::string elmName; + if(root->getArrayNodeName(elmName, num)) { + QList columnData; + std::string value; + QString elmtType = ""; + //root->getValueByName(value, elmName.c_str()); + + UFormElm *elmt = 0; + if(root->getArrayNode(&elmt,0) && elmt) { + if (elmt->isArray()) + elmtType = "Array"; + if (elmt->isStruct()) { + elmtType = "Struct"; + } + if (elmt->isAtom()) { + elmt->getValue(value); + elmtType = "Atom"; + } + if (elmt->isVirtualStruct()) + elmtType = "VirtualStruct"; + columnData << QString(elmName.c_str()) << QString(value.c_str()) << "" << elmtType; + parent->appendChild(new CFormItem(elmt, columnData, parent)); + loadFormData(elmt, parent->child(parent->childCount()-1)); + } + } + num++; + } + } + } + + /******************************************************************************/ + + void CGeorgesFormModel::loadFormHeader() { + + CFormItem *fi_pars = new CFormItem(_rootElm, QList() << "parents", _rootItem); + _rootItem->appendChild(fi_pars); + + Q_FOREACH(QString str, _parents) { + fi_pars->appendChild(new CFormItem(_rootElm, QList() << str, fi_pars)); + } + + /*QStringList dfns = _dependencies["dfn"]; + QStringList typs = _dependencies["typ"]; + + _dependencies.remove("dfn"); + _dependencies.remove("typ"); + + CFormItem *fi_dep = new CFormItem(_rootElm, QList() << "dependencies", _rootItem); + _rootItem->appendChild(fi_dep); + + if (!dfns.isEmpty()) { + CFormItem *fi_dfn = new CFormItem(_rootElm, QList() << "dfn", fi_dep); + fi_dep->appendChild(fi_dfn); + foreach(QString str, dfns) { + fi_dfn->appendChild(new CFormItem(_rootElm, QList() << str, fi_dfn)); + } + } + if (!typs.isEmpty()) { + CFormItem *fi_typ = new CFormItem(_rootElm, QList() << "typ", fi_dep); + fi_dep->appendChild(fi_typ); + foreach(QString str, typs) { + fi_typ->appendChild(new CFormItem(_rootElm, QList() << str, fi_typ)); + } + } + if (!_dependencies.isEmpty()) { + CFormItem *fi_other = new CFormItem(_rootElm, QList() << "other", fi_dep); + fi_dep->appendChild(fi_other); + foreach(QStringList list, _dependencies) { + foreach(QString str, list) { + fi_other->appendChild(new CFormItem(_rootElm, QList() << str, fi_other)); + } + } + }*/ + } + + /******************************************************************************/ + + void CGeorgesFormModel::setupModelData() { + loadFormHeader(); + loadFormData(_rootElm, _rootItem); + } +} /* namespace NLQT */ + +/* end of file */ diff --git a/code/ryzom/tools/leveldesign/georges_editor_qt/src/georgesform_model.h b/code/ryzom/tools/leveldesign/georges_editor_qt/src/georgesform_model.h new file mode 100644 index 000000000..ce25e82b1 --- /dev/null +++ b/code/ryzom/tools/leveldesign/georges_editor_qt/src/georgesform_model.h @@ -0,0 +1,74 @@ +/* +Georges Viewer Qt +Copyright (C) 2010 Adrian Jaekel + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program. If not, see . + +*/ + +#ifndef GEORGESFORM_MODEL_H +#define GEORGESFORM_MODEL_H + +// Qt includes +#include +#include +#include +#include + +// project includes + +namespace NLGEORGES { + class UFormElm; +} + +namespace NLQT { + + class CFormItem; + + class CGeorgesFormModel : public QAbstractItemModel { + Q_OBJECT + + public: + CGeorgesFormModel(NLGEORGES::UFormElm *root, QMap< QString, QStringList> deps, + QString comment, QStringList parents, QObject *parent = 0); + ~CGeorgesFormModel(); + + QVariant data(const QModelIndex &index, int role) const; + bool setData(const QModelIndex &index, const QVariant &value, int role = Qt::EditRole); + Qt::ItemFlags flags(const QModelIndex &index) const; + QVariant headerData(int section, Qt::Orientation orientation, int role = Qt::DisplayRole) const; + QModelIndex index(int row, int column, const QModelIndex &parent = QModelIndex()) const; + QModelIndex parent(const QModelIndex &index) const; + int rowCount(const QModelIndex &parent = QModelIndex()) const; + int columnCount(const QModelIndex &parent = QModelIndex()) const; + CFormItem *getItem(const QModelIndex &index) const; + CGeorgesFormModel *model() { return this; } + + private: + void setupModelData(); + void loadFormData(NLGEORGES::UFormElm *rootElm, CFormItem *parent); + void loadFormHeader(); + + CFormItem* _rootItem; + NLGEORGES::UFormElm* _rootElm; + QMap< QString, QStringList> _dependencies; + QString _comments; + QStringList _parents; + QList* _parentRows; + + };/* class CGeorgesFormModel */ + +} /* namespace NLQT */ + +#endif // GEORGESFORM_MODEL_H diff --git a/code/ryzom/tools/leveldesign/georges_editor_qt/src/georgesform_proxy_model.cpp b/code/ryzom/tools/leveldesign/georges_editor_qt/src/georgesform_proxy_model.cpp new file mode 100644 index 000000000..3847830da --- /dev/null +++ b/code/ryzom/tools/leveldesign/georges_editor_qt/src/georgesform_proxy_model.cpp @@ -0,0 +1,56 @@ +/* + Georges Editor Qt + Copyright (C) 2010 Adrian Jaekel + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . +*/ + +#include "georgesform_proxy_model.h" + +// NeL includes +#include + +namespace NLQT { + + bool CGeorgesFormProxyModel::filterAcceptsRow(int sourceRow, + const QModelIndex &sourceParent) const + { + nlinfo("CGeorgesFormProxyModel::filterAcceptsRow"); + //QModelIndex index0 = sourceModel()->index(sourceRow, 0, sourceParent); + //QModelIndex index1 = sourceModel()->index(sourceRow, 1, sourceParent); + //QModelIndex index2 = sourceModel()->index(sourceRow, 2, sourceParent); + + //return (sourceModel()->data(index0).toString().contains(filterRegExp()) + // || sourceModel()->data(index1).toString().contains(filterRegExp())) + // && dateInRange(sourceModel()->data(index2).toDate()); + + // if (getItem(p_index)->valueFrom() == UFormElm::ValueDefaultDfn) + // return QBrush(QColor(255,0,0,30)); + // if (getItem(p_index)->nodeFrom() == UFormElm::NodeParentForm) + // return QBrush(QColor(0,255,0,30)); + // return QVariant(); + return true; + } + +/******************************************************************************/ + + bool CGeorgesFormProxyModel::filterAcceptsColumn(int sourceRow, + const QModelIndex &sourceParent) const + { + nlinfo("CGeorgesFormProxyModel::filterAcceptsColumn"); + return QSortFilterProxyModel::filterAcceptsColumn(sourceRow, sourceParent); + } +} /* namespace NLQT */ + +/* end of file */ diff --git a/code/ryzom/tools/leveldesign/georges_editor_qt/src/georgesform_proxy_model.h b/code/ryzom/tools/leveldesign/georges_editor_qt/src/georgesform_proxy_model.h new file mode 100644 index 000000000..19fc28c41 --- /dev/null +++ b/code/ryzom/tools/leveldesign/georges_editor_qt/src/georgesform_proxy_model.h @@ -0,0 +1,42 @@ +/* +Georges Viewer Qt +Copyright (C) 2010 Adrian Jaekel + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program. If not, see . + +*/ + +#ifndef GEORGESFORM_PROXY_MODEL_H +#define GEORGESFORM_PROXY_MODEL_H + +// Qt includes +#include + +namespace NLQT { + + class CGeorgesFormProxyModel : public QSortFilterProxyModel { + + public: + CGeorgesFormProxyModel(QObject *parent = 0): QSortFilterProxyModel(parent){} + ~CGeorgesFormProxyModel() {} + + protected: + virtual bool filterAcceptsColumn ( int source_column, const QModelIndex & source_parent ) const ; + virtual bool filterAcceptsRow ( int source_row, const QModelIndex & source_parent ) const ; + + };/* class CGeorgesFormProxyModel */ + +} /* namespace NLQT */ + +#endif // GEORGESFORM_PROXY_MODEL_H diff --git a/code/ryzom/tools/leveldesign/georges_editor_qt/src/images/.directory b/code/ryzom/tools/leveldesign/georges_editor_qt/src/images/.directory new file mode 100644 index 000000000..cb8303c65 --- /dev/null +++ b/code/ryzom/tools/leveldesign/georges_editor_qt/src/images/.directory @@ -0,0 +1,3 @@ +[Dolphin] +ShowPreview=true +Timestamp=2010,6,13,17,20,25 diff --git a/code/ryzom/tools/leveldesign/georges_editor_qt/src/images/go-down.png b/code/ryzom/tools/leveldesign/georges_editor_qt/src/images/go-down.png new file mode 100644 index 0000000000000000000000000000000000000000..780714b8fa8db3e15b9a258bccb3589e57ca5d80 GIT binary patch literal 2404 zcmV-q37htbP)#Yb#qihEXpDal z{6iBL^y9Yow)cF${?2>P=}DU+ zaJy1W_S`=AcTR6l`#iso_q->?hxmVnlrkVE7J5A+Vj*A)5YJ9@kM8Up$Zq@fzH|C` z#s-iVBjX>Md)2Hzy!q}X``$G*zk2vn&D$AcH`c&`6a9Mk`xDdmZ)g&)v=1VkwdaVR zPk0PN*YMzmCR`lO+V|bnR6+(^6aaw&@$Fx}<_pfmP$r8{u5Ca)is$6|>Ui;uUL1L| zPa^{!2shM#@0hSDj*VwvnN>iHYc|q1IELQ-VNmwvjW^($N}cOiuq?ZfDT3$N@acMm z8*RXIOcfnFFi@BX&$Wr>(ire#129dyz$94kouxA1#s=(bY#~XnxfSr2sshsY0S36P z3$xG`@;vySyEFzE*BH|T$cL)H^+3ufGHAkJOJx9>UJPGySn&*8-*U<{@I>(vRe*7( z871(+VP0PaVmnMg7^O>70dfFgl);y>;AIrN7{Vz3;3^$7|Ak}RIOwj?lu6wA^P(g zNHDAa?YFzm8ivufyhex6`23Y;09PGEs1D!AiKMoP=&< zESO6Yr_8WOPbfa0Vn6sih~cs4QzUwxjEx{h(nvt(41e1DB1%e<&j4S%qJb!5`$|_m z^xKOUM!%UfIEqV3XJuUo4g^`2ATof+B!>hCkdF+ZiCLp7)k}#FUXl|fkrAQj`9#-O zMgR$22y9$;JDz%a4>D8cp@~uP1Zlkba#8e=PX~9XH;aM3p(EE8D^ST zm%DIe;F=#Pi<&pxN#R&cT|=_AX{8b@^gw*X*hFk3FhFtcN+e}8xD-7S?^CutC7Lsd z#+nMWG*-e88qyP4w0FIWlkMk_n;67&W+W)o7pzPFdg;1uWM==-_M+yE+ed~6pD3@a zMzXv*KYWsifSjlSEKiw_;gU;aY^I4M1&v~HlB2TBKvh{1MTQm_QTLGZeJSiccm`wX zNjQ!T$F{+w1#4Y*h>XH)RO^HhJ8iJqRp*q??J*SK~a%G(U_@%PE|3CgkmB= z$8?_1HR!53JX}_pYMq?vU?iQz<*^JVGShHf2d<+yBiyzvz_T#c|8HconKJ;}WDT5{ zF35l~(X_E1knPLr>g(!S?j%vVGGK&E=m~I5fTE5M>5X7Tv?K?}t_PyHT>C*c%H zJVgs0naZTPFw}oxS^}T222OV2e?Y@k;7;~uwese(x#_7dS5%bI=CLX-nCk!+023;5 zt}Amq9CTd|hF+1*wRqSAlbq-0gwMHSQv#-Q!k$9#Uis!Q$SP0-k z*XtNb4ZRPr&r|kQ-!ITW3~#dEArnWbm9{36nqIwpr5a>a1zis*LgvkgF#DQ_wj3<1 zK-4zsO?`iKpc6fvXWU@PB=OxKd~gP06T>tQ>G6@_2OC>%MR8dT35^9O^jTGiOhl~{ ziU)D_7RxqMICXeG9Ls*(8an+45Ej8eG!IRueb-$#n(A+DUArDaD?%d5dKe>9YJl@C z6t)jy_2KHoH3!EJJcsni$WbtC^QKbXq8e}~FG^9`aM+rj`if46p8g8tI{dZZLeu8R^237_djWa**6ugOFP-mPwQAF6QOuJ73&cycWp+dH899X) zcJ9FV#lAzDQSq2>j^m~<;O9ocjq+E_iSaGtlc}=SyFLT%$T0gJT-SrmB@XP{iE~E| zr5G2R-OQy)084EkhO{$Tu9tL=_4PiYH`cP{4R^pN;mUyY(fQtSy!yMJ`EP`WE%T_@jc|y=_jR~eG-J5(SQOksyyQ6vJVdr z^wzg*ybq4xIQZO8G1PIUohtMwnRIcpLo2RXqa`b+HtqPi{OFgyA+_Sl3{O_JVG+Qw z2=JyacQP&U{py-3=?`6$654nD+<4cbBnyj#(q%1gc~bTa_w?*>9PK%}U*JQ`gZ~2F Wx`D8V2rwZ40000d4o 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 literal 0 HcmV?d00001 diff --git a/code/ryzom/tools/leveldesign/georges_editor_qt/src/images/khead.png b/code/ryzom/tools/leveldesign/georges_editor_qt/src/images/khead.png new file mode 100644 index 0000000000000000000000000000000000000000..23e50fdb30c5012f7af64abb8ad48170df140751 GIT binary patch literal 1344 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 literal 0 HcmV?d00001 diff --git a/code/ryzom/tools/leveldesign/georges_editor_qt/src/images/open-file.png b/code/ryzom/tools/leveldesign/georges_editor_qt/src/images/open-file.png new file mode 100644 index 0000000000000000000000000000000000000000..7422ad3338bb73f8a30502c3eb830be527c06c98 GIT binary patch literal 1088 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 + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program. If not, see . + +*/ + +#include "log_dialog.h" + +// Qt includes +#include +#include +#include +#include + +// NeL includes + +// Project includes +#include "qt_displayer.h" + +namespace NLQT { + + CGeorgesLogDialog::CGeorgesLogDialog(QWidget *parent): + QDockWidget(parent){ + + _ui.setupUi(this); + + _displayer = new CQtDisplayer(_ui.plainTextEdit); + NLMISC::ErrorLog->addDisplayer(_displayer); + NLMISC::WarningLog->addDisplayer(_displayer); + NLMISC::DebugLog->addDisplayer(_displayer); + NLMISC::AssertLog->addDisplayer(_displayer); + NLMISC::InfoLog->addDisplayer(_displayer); + +} + +CGeorgesLogDialog::~CGeorgesLogDialog() { + NLMISC::ErrorLog->removeDisplayer(_displayer); + NLMISC::WarningLog->removeDisplayer(_displayer); + NLMISC::DebugLog->removeDisplayer(_displayer); + NLMISC::AssertLog->removeDisplayer(_displayer); + NLMISC::InfoLog->removeDisplayer(_displayer); + delete _displayer; +} + +} /* namespace NLQT */ \ No newline at end of file diff --git a/code/ryzom/tools/leveldesign/georges_editor_qt/src/log_dialog.h b/code/ryzom/tools/leveldesign/georges_editor_qt/src/log_dialog.h new file mode 100644 index 000000000..0dab4e9d8 --- /dev/null +++ b/code/ryzom/tools/leveldesign/georges_editor_qt/src/log_dialog.h @@ -0,0 +1,54 @@ +/* + Georges Editor Qt + Copyright (C) 2010 Adrian Jaekel + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . +*/ + +#ifndef LOG_DIALOG_H +#define LOG_DIALOG_H + +// Qt includes +#include + +// STL includes + +// NeL includes +#include + +// Project includes +#include "ui_log_form.h" + +namespace NLQT { + class CQtDisplayer; + +class CGeorgesLogDialog: public QDockWidget +{ + Q_OBJECT + +public: + CGeorgesLogDialog(QWidget *parent = 0); + ~CGeorgesLogDialog(); + +private: + Ui::CGeorgesLogDialog _ui; + + CQtDisplayer *_displayer; + + friend class CMainWindow; +}; /* CGeorgesLogDialog */ + +} /* namespace NLQT */ + +#endif // LOG_DIALOG_H diff --git a/code/ryzom/tools/leveldesign/georges_editor_qt/src/log_form.ui b/code/ryzom/tools/leveldesign/georges_editor_qt/src/log_form.ui new file mode 100644 index 000000000..7a22af13e --- /dev/null +++ b/code/ryzom/tools/leveldesign/georges_editor_qt/src/log_form.ui @@ -0,0 +1,56 @@ + + + CGeorgesLogDialog + + + + 0 + 0 + 472 + 310 + + + + + 0 + 0 + + + + + 89 + 122 + + + + + 524287 + 524287 + + + + Log + + + + + 0 + 0 + + + + + 0 + 100 + + + + + + + + + + + + diff --git a/code/ryzom/tools/leveldesign/georges_editor_qt/src/main.cpp b/code/ryzom/tools/leveldesign/georges_editor_qt/src/main.cpp new file mode 100644 index 000000000..cd2e1ef88 --- /dev/null +++ b/code/ryzom/tools/leveldesign/georges_editor_qt/src/main.cpp @@ -0,0 +1,116 @@ +#include +#include + +// Qt includes +#include +#include +#include +#include + +// NeL includes +#include +#include +#include +#include +#include + +// Project includes +#include "modules.h" + +// nel_qt log file name +#define NLQT_LOG_FILE "nel_qt.log" + +// clear nel_qt log before use +#define NLQT_ERASE_LOG true + +#if !defined (NLQT_USE_LOG_LOG) +# define NLQT_USE_LOG_LOG true +#endif +#if !defined (NLQT_USE_LOG) +# define NLQT_USE_LOG 1 +#endif + +using namespace std; +using namespace NLMISC; + +namespace NLQT { + +namespace { + +CFileDisplayer *s_FileDisplayer = NULL; + +} /* anonymous namespace */ + +} /* namespace NLQT */ + +void messageHandler(QtMsgType p_type, const char* p_msg) { + + fprintf(stderr, "%s\n", p_msg); + + QFile file("qt.log"); + file.open(QIODevice::WriteOnly | QIODevice::Append | QIODevice::Text); + + QChar code; + switch (p_type) { + case QtDebugMsg: code = 'D'; break; + case QtWarningMsg: code = 'W'; break; + case QtCriticalMsg: code = 'C'; break; + case QtFatalMsg: code = 'F'; break; + } + QString dt = QDateTime::currentDateTime().toString("yyyyMMdd hh:mm:ss"); + + QTextStream(&file) << QString("%1 [%2] %3\n").arg(dt).arg(code).arg(QString(p_msg)); +} + +#ifndef DATA_DIR +# define DATA_DIR "." +#endif + + +#ifdef NL_OS_WINDOWS +# ifdef _UNICODE +# define tstring wstring +# else +# define tstring string +# endif +#endif + +sint main(int argc, char **argv) +{ + // go nel! + { + // use log.log if NEL_LOG_IN_FILE and NLQT_USE_LOG_LOG defined as 1 + createDebug(NULL, NLQT_USE_LOG_LOG, false); + if (QFile::exists("qt.log")) + QFile::remove("qt.log"); + + qInstallMsgHandler(messageHandler); +#if NLQT_USE_LOG + // create toverhex_client.log + // filedisplayer only deletes the 001 etc + if (NLQT_ERASE_LOG && CFile::isExists(NLQT_LOG_FILE)) + CFile::deleteFile(NLQT_LOG_FILE); + // initialize the log file + NLQT::s_FileDisplayer = new CFileDisplayer(); + NLQT::s_FileDisplayer->setParam(NLQT_LOG_FILE, NLQT_ERASE_LOG); + DebugLog->addDisplayer(NLQT::s_FileDisplayer); + InfoLog->addDisplayer(NLQT::s_FileDisplayer); + WarningLog->addDisplayer(NLQT::s_FileDisplayer); + AssertLog->addDisplayer(NLQT::s_FileDisplayer); + ErrorLog->addDisplayer(NLQT::s_FileDisplayer); +#endif + + nlinfo("Welcome to NeL!"); + + NLMISC::CPath::remapExtension("tga", "png", true); + } + + QApplication app(argc, argv); + + Modules::init(); + //Modules::mainWin().resize(800,600); + Modules::mainWin().show(); + int result = app.exec(); + Modules::release(); + return result; +} diff --git a/code/ryzom/tools/leveldesign/georges_editor_qt/src/main_window.cpp b/code/ryzom/tools/leveldesign/georges_editor_qt/src/main_window.cpp new file mode 100644 index 000000000..d2ce4d887 --- /dev/null +++ b/code/ryzom/tools/leveldesign/georges_editor_qt/src/main_window.cpp @@ -0,0 +1,488 @@ +/* + Georges Editor Qt + Copyright (C) 2010 Adrian Jaekel + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . +*/ + +#include "main_window.h" + +// STL includes + +// Qt includes +#include + +// NeL includes + +// Project includes +#include "modules.h" +#include "settings_dialog.h" +#include "log_dialog.h" +#include "objectviewer_dialog.h" +#include "georges_dirtree_dialog.h" +#include "georges_treeview_dialog.h" + +using namespace std; +using namespace NLMISC; + +namespace NLQT { + + +CMainWindow::CMainWindow(QWidget *parent) + : QMainWindow(parent), + _GeorgesLogDialog(0), _ObjectViewerDialog(0), + _GeorgesDirTreeDialog(0) +{ + setWindowTitle("Qt Georges Editor"); + + setDockNestingEnabled(true); + setCentralWidget(0); + setCorner(Qt::TopLeftCorner, Qt::LeftDockWidgetArea); + setCorner(Qt::BottomLeftCorner, Qt::LeftDockWidgetArea); + + // create log dock widget + _GeorgesLogDialog = new CGeorgesLogDialog(this); + addDockWidget(Qt::RightDockWidgetArea, _GeorgesLogDialog); + + // empty form view as placeholder + createEmptyView(); + _currentView = 0; + + // load and set leveldesign path from config + QString ldPath = Modules::config().configLeveldesignPath().c_str(); + QFileInfo info(ldPath); + if (!info.isDir()) ldPath = ""; + + // create georges dir dock widget + _GeorgesDirTreeDialog = new CGeorgesDirTreeDialog(ldPath, this); + addDockWidget(Qt::LeftDockWidgetArea, _GeorgesDirTreeDialog); + if (ldPath == "") { + if (QMessageBox::information(this, tr("Missing leveldesign path"), + tr("Your leveldesign path seems to be empty or incorrect.\nDo you want to set it now?"), + QMessageBox::Ok | QMessageBox::Cancel) == QMessageBox::Ok) { + settings(); + } + } + + // create NeL viewport dock widget + _ObjectViewerDialog = new CObjectViewerDialog(this); + //_ObjectViewerDialog->setAllowedAreas(Qt::LeftDockWidgetArea ); + //_ObjectViewerDialog->hide(); + addDockWidget(Qt::LeftDockWidgetArea, _ObjectViewerDialog); + + createActions(); + createMenus(); + createToolBars(); + createStatusBar(); + + //_ObjectViewerDialog->toggleViewAction()->trigger(); + QSettings settings("georges_editor_qt.ini", QSettings::IniFormat); + settings.beginGroup("WindowSettings"); + restoreState(settings.value("QtWindowState").toByteArray()); + restoreGeometry(settings.value("QtWindowGeometry").toByteArray()); + settings.endGroup(); + + // setup Qt style and palette from config file + //_originalPalette = QApplication::palette(); + //Modules::config().setAndCallback("QtStyle", CConfigCallback(this, &CMainWindow::cfcbQtStyle)); + //Modules::config().setAndCallback("QtPalette", CConfigCallback(this, &CMainWindow::cfcbQtPalette)); + + setWindowIcon(QIcon(":/images/khead.png")); + + _statusBarTimer = new QTimer(this); + connect(_statusBarTimer, SIGNAL(timeout()), this, SLOT(updateStatusBar())); + _statusBarTimer->start(5000); + + connect(_GeorgesDirTreeDialog, SIGNAL(selectedForm(QString)), + this, SLOT(openTreeView(QString))); +} + +CMainWindow::~CMainWindow() +{ + // save state & geometry of window and widgets + QSettings settings("georges_editor_qt.ini", QSettings::IniFormat); + settings.beginGroup("WindowSettings"); + settings.setValue("QtWindowState", saveState()); + settings.setValue("QtWindowGeometry", saveGeometry()); + settings.endGroup(); + + //Modules::config().dropCallback("QtPalette"); + //Modules::config().dropCallback("QtStyle"); + + _statusBarTimer->stop(); + + delete _ObjectViewerDialog; + delete _GeorgesDirTreeDialog; + delete _GeorgesLogDialog; +} + +void CMainWindow::openTreeView(QString file) { + // create or/and raise tree view dock widget for current file + + setCurrentFile(file); + + CGeorgesTreeViewDialog *newView = 0; + + Q_FOREACH(CGeorgesTreeViewDialog* dlg, _treeViewList) { + if (dlg->loadedForm == file) + newView = dlg; + } + if (!newView) { + newView = new CGeorgesTreeViewDialog(this); + //newView->setAllowedAreas(Qt::TopDockWidgetArea | Qt::LeftDockWidgetArea | Qt::RightDockWidgetArea); + newView->setWindowTitle(file); + + if (_treeViewList.isEmpty()) { + _emptyView->deleteLater(); + addDockWidget(Qt::TopDockWidgetArea, newView); + } else { + tabifyDockWidget(_treeViewList.first(),newView); + QTabBar* tb = Modules::mainWin().getTabBar(); + if (tb) { + disconnect(tb, SIGNAL(currentChanged ( int ) ), + this,SLOT(tabChanged(int))); + connect(tb, SIGNAL(currentChanged ( int ) ), + this,SLOT(tabChanged(int))); + } + } + + _treeViewList.append(newView); + newView->selectedForm(file); + _currentView = newView; + + connect(newView, SIGNAL(changeFile(QString)), + _GeorgesDirTreeDialog, SLOT(changeFile(QString))); + connect(newView, SIGNAL(modified(bool)), + _saveAction, SLOT(setEnabled(bool))); + } + newView->raise(); +} + +void CMainWindow::settings() +{ + CSettingsDialog _settingsDialog(this); + + connect(&_settingsDialog,SIGNAL(ldPathChanged(QString)), + _GeorgesDirTreeDialog,SLOT(ldPathChanged(QString))); + + //_settingsDialog.show(); + _settingsDialog.exec(); +} + +void CMainWindow::about() +{ + QMessageBox::about(this, tr("About Georges Viewer Qt"), + tr("

Georges Viewer Qt

" + "Author: aquiles
Credits:Thx to dnk-88 for parts of his code")); +} + +void CMainWindow::updateStatusBar() +{ + //if (_isGraphicsInitialized) + // statusBar()->showMessage(QString(Modules::objView().getDriver()->getVideocardInformation())); +} + +void CMainWindow::open() +{ + /*QStringList fileNames = QFileDialog::getOpenFileNames(this, + tr("Open NeL data file"), _lastDir, + tr("All NeL files (*.shape *.ps);;" + "NeL shape files (*.shape);;" + "NeL particle system files (*.ps)")); + + setCursor(Qt::WaitCursor); + if (!fileNames.isEmpty()) + { + QStringList list = fileNames; + QStringList::Iterator it = list.begin(); + _lastDir = QFileInfo(*it).absolutePath(); + + QString skelFileName = QFileDialog::getOpenFileName(this, + tr("Open skeleton file"), _lastDir, + tr("NeL skeleton file (*.skel)")); + + while(it != list.end()) + { + loadFile(*it, skelFileName); + ++it; + } + _AnimationSetDialog->updateListObject(); + _AnimationSetDialog->updateListAnim(); + _SlotManagerDialog->updateUiSlots(); + } + setCursor(Qt::ArrowCursor);*/ +} + +void CMainWindow::save() +{ + if(!_currentView) + return; + + setCursor(Qt::WaitCursor); + + _currentView->write(); + setWindowTitle(windowTitle().remove("*")); + _saveAction->setEnabled(false); + + setCursor(Qt::ArrowCursor); +} + +void CMainWindow::create() +{ +} + +void CMainWindow::createEmptyView() +{ + _emptyView = new CGeorgesTreeViewDialog(this, true); + //_emptyView->setAllowedAreas(Qt::TopDockWidgetArea); + addDockWidget(Qt::TopDockWidgetArea,_emptyView); +} + +void CMainWindow::createActions() +{ + _openAction = new QAction(tr("&Open..."), this); + _openAction->setIcon(QApplication::style()->standardIcon(QStyle::SP_DialogOpenButton)); + _openAction->setShortcut(QKeySequence::Open); + _openAction->setStatusTip(tr("Open an existing file")); + connect(_openAction, SIGNAL(triggered()), this, SLOT(open())); + + _createAction = new QAction(tr("&New..."), this); + _createAction->setIcon(QApplication::style()->standardIcon(QStyle::SP_FileDialogNewFolder)); + _createAction->setShortcut(QKeySequence::New); + _createAction->setStatusTip(tr("Create a new file")); + connect(_createAction, SIGNAL(triggered()), this, SLOT(create())); + + _saveAction = new QAction(tr("&Save..."), this); + _saveAction->setIcon(QApplication::style()->standardIcon(QStyle::SP_DialogSaveButton)); + _saveAction->setShortcut(QKeySequence::Save); + _saveAction->setStatusTip(tr("Saves the current file")); + _saveAction->setDisabled(true); + connect(_saveAction, SIGNAL(triggered()), this, SLOT(save())); + + _exitAction = new QAction(tr("E&xit"), this); + _exitAction->setShortcut(QKeySequence::Close); + _exitAction->setIcon(QApplication::style()->standardIcon(QStyle::SP_DialogCloseButton)); + _exitAction->setStatusTip(tr("Exit the application")); + connect(_exitAction, SIGNAL(triggered()), this, SLOT(close())); + + _setBackColorAction = _ObjectViewerDialog->createSetBackgroundColor(this); + _setBackColorAction->setText(tr("Set &background color")); + _setBackColorAction->setStatusTip(tr("Set background color")); + + _settingsAction = new QAction(tr("&Settings"), this); + _settingsAction->setIcon(QIcon(":/images/preferences.png")); + _settingsAction->setStatusTip(tr("Settings")); + connect(_settingsAction, SIGNAL(triggered()), this, SLOT(settings())); + + _aboutAction = new QAction(tr("&About"), this); + _aboutAction->setStatusTip(tr("Show the application's About box")); + connect(_aboutAction, SIGNAL(triggered()), this, SLOT(about())); + + _aboutQtAction = new QAction(tr("About &Qt"), this); + _aboutQtAction->setStatusTip(tr("Show the Qt library's About box")); + connect(_aboutQtAction, SIGNAL(triggered()), qApp, SLOT(aboutQt())); + + for (int i = 0; i < MaxRecentFiles; ++i) { + recentFileActs[i] = new QAction(this); + recentFileActs[i]->setVisible(false); + connect(recentFileActs[i], SIGNAL(triggered()), + this, SLOT(openRecentFile())); + } +} + +void CMainWindow::createMenus() +{ + _fileMenu = menuBar()->addMenu(tr("&File")); + _fileMenu->addAction(_createAction); + _fileMenu->addAction(_openAction); + _fileMenu->addAction(_saveAction); + _separatorAction = _fileMenu->addSeparator(); + for (int i = 0; i < MaxRecentFiles; ++i) + _fileMenu->addAction(recentFileActs[i]); + _fileMenu->addSeparator(); + _fileMenu->addAction(_exitAction); + updateRecentFileActions(); + + _viewMenu = menuBar()->addMenu(tr("&View")); + _viewMenu->addAction(_setBackColorAction); + if (_GeorgesDirTreeDialog) + _viewMenu->addAction(_GeorgesDirTreeDialog->toggleViewAction()); + + _toolsMenu = menuBar()->addMenu(tr("&Tools")); + if (_ObjectViewerDialog) { + _toolsMenu->addAction(_ObjectViewerDialog->toggleViewAction()); + _ObjectViewerDialog->toggleViewAction()->setIcon(QIcon(":/images/pqrticles.png")); + } + _toolsMenu->addSeparator(); + _toolsMenu->addAction(_settingsAction); + + menuBar()->addSeparator(); + + _helpMenu = menuBar()->addMenu(tr("&Help")); + _helpMenu->addAction(_aboutAction); + _helpMenu->addAction(_aboutQtAction); +} + +void CMainWindow::createToolBars() +{ + _fileToolBar = addToolBar(tr("&File")); + _fileToolBar->addAction(_createAction); + _fileToolBar->addAction(_openAction); + _fileToolBar->addAction(_saveAction); + + _toolsBar = addToolBar(tr("&Tools")); + if (_ObjectViewerDialog) + _toolsBar->addAction(_ObjectViewerDialog->toggleViewAction()); +} + +void CMainWindow::createStatusBar() +{ + statusBar()->showMessage(tr("StatusReady")); +} + +void CMainWindow::cfcbQtStyle(NLMISC::CConfigFile::CVar &var) +{ + QApplication::setStyle(QStyleFactory::create(var.asString().c_str())); +} + +void CMainWindow::cfcbQtPalette(NLMISC::CConfigFile::CVar &var) +{ + if (var.asBool()) QApplication::setPalette(QApplication::style()->standardPalette()); + else QApplication::setPalette(_originalPalette); +} + +QTabBar* CMainWindow::getTabBar() +{ + // get the QTabBar + QList tabList = findChildren(); + //tabList = _mainWindow->findChildren(); + //nlinfo(QString("%1 %2").arg(QString::number((int)this,16)). + // arg(QString::number((int)_mainWindow,16)). + // toStdString().c_str()); + QTabBar *tb = 0; + Q_FOREACH(QTabBar *tabBar, tabList){ + if (tabBar->parent() != this) + continue; + //nlinfo(QString("%1 %2 %3 %4").arg(tabBar->objectName()). + // arg(QString::number((int)tabBar,16)). + // arg(QString::number((int)tabBar->parentWidget(),16)). + // arg(QString::number((int)tabBar->parent(),16)). + // toStdString().c_str()); + for (int i = 0; i < tabBar->count(); i++) { + QString currentTab = tabBar->tabText(i); + //nlinfo(currentTab.toStdString().c_str()); + } + tb = tabBar; + } + return tb; +} + +void CMainWindow::tabChanged(int index) +{ + if (index == -1) { + setWindowTitle("Qt Georges Editor"); + return; + } + + QTabBar *tb = getTabBar(); + //nlinfo(QString("%1").arg(index).toStdString().c_str()); + + Q_FOREACH(CGeorgesTreeViewDialog* dlg, _treeViewList) { + if (dlg->windowTitle() == tb->tabText(index)) { + //nlinfo(QString("%1 modified %2").arg(tb->tabText(index)). + // arg(dlg->modified()). + // toStdString().c_str()); + _currentView = dlg; + setWindowTitle("Qt Georges Editor - " + tb->tabText(index)); + _saveAction->setEnabled(dlg->modified()); + } + } +} + + void CMainWindow::openRecentFile() + { + QAction *action = qobject_cast(sender()); + if (action) + loadFile(action->data().toString()); + } + + void CMainWindow::setCurrentFile(const QString &fileName) + { + //curFile = fileName; + //setWindowFilePath(curFile); + + QSettings settings("georges_editor_qt.ini", QSettings::IniFormat); + settings.beginGroup("RecentFileList"); + QStringList files = settings.value("List").toStringList(); + settings.endGroup(); + + files.removeAll(fileName); + files.prepend(fileName); + while (files.size() > MaxRecentFiles) + files.removeLast(); + + settings.beginGroup("RecentFileList"); + settings.setValue("List",files); + settings.endGroup(); + + Q_FOREACH (QWidget *widget, QApplication::topLevelWidgets()) { + CMainWindow *mainWin = qobject_cast(widget); + if (mainWin) + mainWin->updateRecentFileActions(); + } + } + + void CMainWindow::updateRecentFileActions() + { + QSettings settings("georges_editor_qt.ini", QSettings::IniFormat); + settings.beginGroup("RecentFileList"); + QStringList files = settings.value("List").toStringList(); + settings.endGroup(); + int numRecentFiles = qMin(files.size(), (int)MaxRecentFiles); + + for (int i = 0; i < numRecentFiles; ++i) { + QString text = tr("&%1 %2").arg(i + 1).arg(QFileInfo(files[i]).fileName()); + recentFileActs[i]->setText(text); + recentFileActs[i]->setData(files[i]); + recentFileActs[i]->setVisible(true); + } + for (int j = numRecentFiles; j < MaxRecentFiles; ++j) + recentFileActs[j]->setVisible(false); + + _separatorAction->setVisible(numRecentFiles > 0); + } + + void CMainWindow::loadFile(const QString &fileName) + { + /*QFile file(fileName); + if (!file.open(QFile::ReadOnly | QFile::Text)) { + QMessageBox::warning(this, tr("Recent Files"), + tr("Cannot read file %1:\n%2.") + .arg(fileName) + .arg(file.errorString())); + return; + } + + QTextStream in(&file); + QApplication::setOverrideCursor(Qt::WaitCursor); + textEdit->setPlainText(in.readAll()); + QApplication::restoreOverrideCursor();*/ + + openTreeView(fileName); + setCurrentFile(fileName); + //statusBar()->showMessage(tr("File loaded"), 2000); + } +} /* namespace NLQT */ + +/* end of file */ diff --git a/code/ryzom/tools/leveldesign/georges_editor_qt/src/main_window.h b/code/ryzom/tools/leveldesign/georges_editor_qt/src/main_window.h new file mode 100644 index 000000000..fa616e7bb --- /dev/null +++ b/code/ryzom/tools/leveldesign/georges_editor_qt/src/main_window.h @@ -0,0 +1,122 @@ +/* + Georges Editor Qt + Copyright (C) 2010 Adrian Jaekel + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + +*/ + +#ifndef MAIN_WINDOW_H +#define MAIN_WINDOW_H +#include + +// STL includes + +// Qt includes + +#include +#include + +// NeL includes +#include + +// Project includes + +namespace NLMISC { + class CConfigFile; +} + +namespace NLQT { + + class CGeorgesLogDialog; + class CObjectViewerDialog; + class CGeorgesDirTreeDialog; + class CGeorgesTreeViewDialog; + + +class CMainWindow : public QMainWindow +{ + Q_OBJECT + +public: + CMainWindow(QWidget *parent = 0); + ~CMainWindow(); + + CGeorgesTreeViewDialog* getEmptyView() { return _emptyView;} + QList& getTreeViewList() { return _treeViewList; } + QTabBar* getTabBar(); + void createEmptyView(); + +private Q_SLOTS: + void open(); + void create(); + void save(); + void settings(); + void about(); + void updateStatusBar(); + void openTreeView(QString); + void tabChanged(int); + void openRecentFile(); + +private: + void createActions(); + void createMenus(); + void createToolBars(); + void createStatusBar(); + void createDialogs(); + + void loadFile(const QString &fileName); + void updateRecentFileActions(); + void setCurrentFile(const QString &fileName); + + void cfcbQtStyle(NLMISC::CConfigFile::CVar &var); + void cfcbQtPalette(NLMISC::CConfigFile::CVar &var); + + CGeorgesLogDialog *_GeorgesLogDialog; + CObjectViewerDialog *_ObjectViewerDialog; + CGeorgesDirTreeDialog *_GeorgesDirTreeDialog; + QList _treeViewList; + CGeorgesTreeViewDialog *_emptyView; + CGeorgesTreeViewDialog *_currentView; + + QPalette _originalPalette; + + QTimer *_statusBarTimer; + + QMenu *_fileMenu; + QMenu *_viewMenu; + QMenu *_toolsMenu; + QMenu *_helpMenu; + QToolBar *_fileToolBar; + QToolBar *_editToolBar; + QToolBar *_toolsBar; + QAction *_openAction; + QAction *_createAction; + QAction *_saveAction; + QAction *_exitAction; + QAction *_setBackColorAction; + QAction *_settingsAction; + QAction *_aboutAction; + QAction *_aboutQtAction; + QAction *_separatorAction; + + + enum { MaxRecentFiles = 5 }; + QAction *recentFileActs[MaxRecentFiles]; + +};/* class CMainWindow */ + +} /* namespace NLQT */ + +#endif // MAIN_WINDOW_H diff --git a/code/ryzom/tools/leveldesign/georges_editor_qt/src/modules.cpp b/code/ryzom/tools/leveldesign/georges_editor_qt/src/modules.cpp new file mode 100644 index 000000000..4dc5f462c --- /dev/null +++ b/code/ryzom/tools/leveldesign/georges_editor_qt/src/modules.cpp @@ -0,0 +1,44 @@ +/* + Georges Editor Qt + Copyright (C) 2010 Adrian Jaekel + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . +*/ + +#include "modules.h" + +NLQT::CConfiguration *Modules::_configuration = NULL; +NLQT::CObjectViewer *Modules::_objectViewer = NULL; +NLQT::CGeorges *Modules::_georges = NULL; +NLQT::CMainWindow *Modules::_mainWindow = NULL; + +void Modules::init() +{ + if (_configuration == NULL) _configuration = new NLQT::CConfiguration; + config().init(); + + if (_objectViewer == NULL) _objectViewer = new NLQT::CObjectViewer; + if (_georges == NULL) _georges = new NLQT::CGeorges; + if (_mainWindow == NULL) _mainWindow = new NLQT::CMainWindow; +} + +void Modules::release() +{ + delete _mainWindow; _mainWindow = NULL; + delete _objectViewer; _objectViewer = NULL; + delete _georges; _georges = NULL; + + config().release(); + delete _configuration; _configuration = NULL; +} diff --git a/code/ryzom/tools/leveldesign/georges_editor_qt/src/modules.h b/code/ryzom/tools/leveldesign/georges_editor_qt/src/modules.h new file mode 100644 index 000000000..9a156ab41 --- /dev/null +++ b/code/ryzom/tools/leveldesign/georges_editor_qt/src/modules.h @@ -0,0 +1,44 @@ +/* + Georges Editor Qt + Copyright (C) 2010 Adrian Jaekel + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . +*/ + +#ifndef MODULES_H +#define MODULES_H + +#include "configuration.h" +#include "object_viewer.h" +#include "main_window.h" +#include "georges.h" + +class Modules +{ +public: + static void init(); + static void release(); + + static NLQT::CConfiguration &config() { return *_configuration; } + static NLQT::CObjectViewer &objView() { return *_objectViewer; } + static NLQT::CGeorges &georges() { return *_georges;} + static NLQT::CMainWindow &mainWin() { return *_mainWindow; } +private: + static NLQT::CConfiguration *_configuration; + static NLQT::CObjectViewer *_objectViewer; + static NLQT::CMainWindow *_mainWindow; + static NLQT::CGeorges *_georges; +}; + +#endif // MODULES_H diff --git a/code/ryzom/tools/leveldesign/georges_editor_qt/src/object_viewer.cpp b/code/ryzom/tools/leveldesign/georges_editor_qt/src/object_viewer.cpp new file mode 100644 index 000000000..a819d09b3 --- /dev/null +++ b/code/ryzom/tools/leveldesign/georges_editor_qt/src/object_viewer.cpp @@ -0,0 +1,411 @@ +/* + Georges Editor Qt + Copyright (C) 2010 Adrian Jaekel + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . +*/ + +#include "object_viewer.h" + +// STL includes + +// NeL includes +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +// Project includes +#include "modules.h" +#include "configuration.h" + +using namespace std; +using namespace NLMISC; +using namespace NL3D; + +namespace NLQT { + +CObjectViewer::CObjectViewer() + : _Driver(NULL), + _phi(0), _psi(0),_dist(20), + _CurrentInstance("") +{ + +} + +CObjectViewer::~CObjectViewer() +{ + +} + +void CObjectViewer::reinit(nlWindow wnd, uint16 w, uint16 h) +{ + nldebug("CObjectViewert::reinit"); + + //release(); + //init(wnd, w, h); + _Driver->setDisplay(wnd, NL3D::UDriver::CMode(w, h, 32)); +} + +void CObjectViewer::init(nlWindow wnd, uint16 w, uint16 h) +{ + //H_AUTO2 + nldebug("CObjectViewer::init"); + + // load and set remap extensions from config + //Modules::config().configRemapExtensions(); + + // load and set search paths from config + //Modules::config().configSearchPaths(); + + // set background color from config + Modules::config().setAndCallback("BackgroundColor", CConfigCallback(this, &CObjectViewer::cfcbBackgroundColor)); + + // set graphics driver from config + Modules::config().setAndCallback("GraphicsDriver",CConfigCallback(this,&CObjectViewer::cfcbGraphicsDriver)); + + // create the driver + nlassert(!_Driver); + + _Driver = UDriver::createDriver(NULL, _Direct3D, NULL); + nlassert(_Driver); + + // initialize the window with config file values + _Driver->setDisplay(wnd, NL3D::UDriver::CMode(w, h, 32)); + + _Light = ULight::createLight(); + + // set mode of the light + _Light->setMode(ULight::DirectionalLight); + + // set position of the light + _Light->setPosition(CVector(-20.f, 30.f, 10.f)); + + // white light + _Light->setAmbiant(CRGBA(255, 255, 255)); + + // set and enable the light + _Driver->setLight(0, *_Light); + _Driver->enableLight(0); + + // Create a scene + _Scene = _Driver->createScene(true); + + _PlayListManager = _Scene->createPlayListManager(); + + _Scene->enableLightingSystem(true); + + // create the camera + UCamera camera = _Scene->getCam(); + + camera.setTransformMode (UTransformable::DirectMatrix); + + setSizeViewport(w, h); + + // camera will look at entities + updateCamera(0,0,0); + + NLMISC::CVector hotSpot=NLMISC::CVector(0,0,0); + + _MouseListener = _Driver->create3dMouseListener(); + _MouseListener->setMatrix(Modules::objView().getScene()->getCam().getMatrix()); + _MouseListener->setFrustrum(Modules::objView().getScene()->getCam().getFrustum()); + _MouseListener->setHotSpot(hotSpot); + _MouseListener->setMouseMode(U3dMouseListener::edit3d); +} + +void CObjectViewer::release() +{ + //H_AUTO2 + nldebug("CObjectViewer::release"); + + Modules::config().dropCallback("BackgroundColor"); + Modules::config().dropCallback("GraphicsDriver"); + + _Driver->delete3dMouseListener(_MouseListener); + + // delete all entities + deleteEntities(); + + _Scene->deletePlayListManager(_PlayListManager); + + // delete the scene + _Driver->deleteScene(_Scene); + + // delete the light + delete _Light; + + // release driver + nlassert(_Driver); + _Driver->release(); + delete _Driver; + _Driver = NULL; +} + +void CObjectViewer::updateInput() +{ + _Driver->EventServer.pump(); + + // New matrix from camera + _Scene->getCam().setTransformMode(NL3D::UTransformable::DirectMatrix); + _Scene->getCam().setMatrix (_MouseListener->getViewMatrix()); +} + +void CObjectViewer::renderDriver() +{ + _Driver->clearBuffers(_BackgroundColor); +} + +void CObjectViewer::renderScene() +{ + // render the scene + _Scene->render(); +} + +void CObjectViewer::renderDebug2D() +{ +} + +void CObjectViewer::saveScreenshot(const std::string &nameFile, bool jpg, bool png, bool tga) +{ + //H_AUTO2 + + // FIXME: create screenshot path if it doesn't exist! + + // empty bitmap + CBitmap bitmap; + // copy the driver buffer to the bitmap + _Driver->getBuffer(bitmap); + // create the file name + string filename = std::string("./") + nameFile; + // write the bitmap as a jpg, png or tga to the file + if (jpg) + { + string newfilename = CFile::findNewFile(filename + ".jpg"); + COFile outputFile(newfilename); + bitmap.writeJPG(outputFile, 100); + nlinfo("Screenshot '%s' saved", newfilename.c_str()); + } + if (png) + { + string newfilename = CFile::findNewFile(filename + ".png"); + COFile outputFile(newfilename); + bitmap.writePNG(outputFile, 24); + nlinfo("Screenshot '%s' saved", newfilename.c_str()); + } + if (tga) + { + string newfilename = CFile::findNewFile(filename + ".tga"); + COFile outputFile(newfilename); + bitmap.writeTGA(outputFile, 24, false); + nlinfo("Screenshot '%s' saved", newfilename.c_str()); + } +} + +bool CObjectViewer::loadMesh(const std::string &meshFileName, const std::string &skelFileName) +{ + CPath::addSearchPath(CFile::getPath(meshFileName), false, false); + + // create instance of the mesh character + UInstance Entity = _Scene->createInstance(meshFileName); + + USkeleton Skeleton = _Scene->createSkeleton(skelFileName); + + // if we can't create entity, skip it + if (Entity.empty()) return false; + + // create a new entity + EIT eit = (_Entities.insert (make_pair (CFile::getFilenameWithoutExtension(meshFileName), CEntity()))).first; + CEntity &entity = (*eit).second; + + // set the entity up + entity._Name = CFile::getFilenameWithoutExtension(meshFileName); + entity._Instance = Entity; + if (!Skeleton.empty()) + { + entity._Skeleton = Skeleton; + entity._Skeleton.bindSkin (entity._Instance); + } + entity._AnimationSet = _Driver->createAnimationSet(false); + entity._PlayList = _PlayListManager->createPlayList(entity._AnimationSet); + return true; +} + +void CObjectViewer::resetScene() +{ + deleteEntities(); + + // Reset camera. + //.. + + // to load files with the same name but located in different directories + //CPath::clearMap(); + + // load and set search paths from config + //Modules::config().configSearchPaths(); + + _CurrentInstance = ""; + + nlinfo("Scene cleared"); +} + +void CObjectViewer::updateCamera(float deltaPsi, float deltaPhi, float deltaDist) +{ + _phi += deltaPhi; + _psi += deltaPsi; + _dist += deltaDist; + + if(_phi < -NLMISC::Pi/2) _phi -= deltaPhi; + if(_phi > NLMISC::Pi/2) _phi -= deltaPsi; + if (_dist < 1) _dist = 1; + + NLMISC::CQuat q0,q1,q2; + NLMISC::CVector up(0,0,1); + NLMISC::CVector v(0,0,1); + + q0.setAngleAxis(v,_psi); + v = NLMISC::CVector(0,1,0); + q1.setAngleAxis(v,_phi); + q2 = q0 * q1; + NLMISC::CMatrix m0; + m0.setRot(q2); + NLMISC::CVector camera = m0 * NLMISC::CVector(_dist,0,0); + + _Scene->getCam().lookAt(camera, up); +} + +void CObjectViewer::setBackgroundColor(NLMISC::CRGBA backgroundColor) +{ + _BackgroundColor = backgroundColor; + + // config file variable changes + Modules::config().getConfigFile().getVar("BackgroundColor").setAsInt(_BackgroundColor.R, 0); + Modules::config().getConfigFile().getVar("BackgroundColor").setAsInt(_BackgroundColor.G, 1); + Modules::config().getConfigFile().getVar("BackgroundColor").setAsInt(_BackgroundColor.B, 2); +} + +void CObjectViewer::setGraphicsDriver(bool Direct3D) +{ + _Direct3D = Direct3D; + + if (_Direct3D) Modules::config().getConfigFile().getVar("GraphicsDriver").setAsString("Direct3D"); + else Modules::config().getConfigFile().getVar("GraphicsDriver").setAsString("OpenGL"); +} + +void CObjectViewer::setSizeViewport(uint16 w, uint16 h) +{ + _Scene->getCam().setPerspective((float)Pi/2.f, (float)w/h, 0.1f, 1000); +} + +void CObjectViewer::getSizeViewport(float &left, float &right, float &bottom, float &top, float &znear, float &zfar) +{ + //_Scene->getCam().setPerspective((float)Pi/2.f, (float)w/h, 0.1f, 1000); + _Scene->getCam().getFrustum(left, right, bottom, top, znear, zfar); +} + +void CObjectViewer::setCurrentObject(const std::string &name) +{ + if ((_Entities.count(name) != 0) || ( name.empty() )) _CurrentInstance = name; + else nlerror ("Entity %s not found", name.c_str()); + nlinfo("set current entity %s", _CurrentInstance.c_str()); +} + +CEntity& CObjectViewer::getEntity(const std::string &name) +{ + if ( _Entities.count(name) == 0) nlerror("Entity %s not found", name.c_str()); + EIT eit = _Entities.find (name); + return (*eit).second; +} + +void CObjectViewer::getListObjects(std::vector &listObj) +{ + listObj.clear(); + for (EIT eit = _Entities.begin(); eit != _Entities.end(); ++eit) + listObj.push_back((*eit).second._Name); +} + +void CObjectViewer::deleteEntity(CEntity &entity) +{ + if (entity._PlayList != NULL) + { + _PlayListManager->deletePlayList (entity._PlayList); + entity._PlayList = NULL; + } + + if (entity._AnimationSet != NULL) + { + _Driver->deleteAnimationSet(entity._AnimationSet); + entity._AnimationSet = NULL; + } + + if (!entity._Skeleton.empty()) + { + entity._Skeleton.detachSkeletonSon(entity._Instance); + + _Scene->deleteSkeleton(entity._Skeleton); + entity._Skeleton = NULL; + } + + if (!entity._Instance.empty()) + { + _Scene->deleteInstance(entity._Instance); + entity._Instance = NULL; + } +} + +void CObjectViewer::deleteEntities() +{ + for (EIT eit = _Entities.begin(); eit != _Entities.end(); ++eit) + { + CEntity &entity = (*eit).second; + deleteEntity(entity); + } + _Entities.clear(); +} + +void CObjectViewer::cfcbBackgroundColor(NLMISC::CConfigFile::CVar &var) +{ + // read variable from config file + _BackgroundColor = CRGBA(var.asInt(0), var.asInt(1), var.asInt(2)); +} + +void CObjectViewer::cfcbGraphicsDriver(NLMISC::CConfigFile::CVar &var) +{ + // Choose driver opengl to work correctly under Linux example + _Direct3D = false; //_Driver = OpenGL; + +#ifdef NL_OS_WINDOWS + std::string driver = var.asString(); + if (driver == "Direct3D") _Direct3D = true; //m_Driver = Direct3D; + else if (driver == "OpenGL") _Direct3D = false; //m_Driver = OpenGL; + else nlwarning("Invalid driver specified, defaulting to OpenGL"); +#endif +} + +} /* namespace NLQT */ diff --git a/code/ryzom/tools/leveldesign/georges_editor_qt/src/object_viewer.h b/code/ryzom/tools/leveldesign/georges_editor_qt/src/object_viewer.h new file mode 100644 index 000000000..6da05a64c --- /dev/null +++ b/code/ryzom/tools/leveldesign/georges_editor_qt/src/object_viewer.h @@ -0,0 +1,191 @@ +/* + Georges Editor Qt + Copyright (C) 2010 Adrian Jaekel + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . +*/ + +#ifndef OBJECT_VIEWER_H +#define OBJECT_VIEWER_H + +#include + +// STL includes +#include +#include + +// NeL includes +#include +#include +#include + +// Project includes +#include "entity.h" + +namespace NL3D { + class UDriver; + class UScene; + class ULight; + class UInstance; + class UCamera; + class USkeleton; + class UPlayListManager; + class U3dMouseListener; +} + +/** +namespace NLQT +@brief namespace NLQT +*/ +namespace NLQT { + +/** +@class CObjectViewer +A CObjectViewer class loading and viewing shape, particle system files. +*/ +class CObjectViewer +{ +public: + /// Default constructor. + CObjectViewer(); + + virtual ~CObjectViewer(); + + /// Init a driver and create scene. + /// @param wnd - handle window. + /// @param w - width window. + /// @param h - height window. + void init(nlWindow wnd, uint16 w, uint16 h); + + void reinit(nlWindow wnd, uint16 w, uint16 h); + + /// Release class. + void release(); + + /// Update mouse and keyboard events. And update camera matrix. + void updateInput(); + + /// Render Driver (clear all buffers and set background color). + void renderDriver(); + + /// Render current scene. + void renderScene(); + + /// Render Debug 2D (stuff for dev). + void renderDebug2D(); + + /// Make a screenshot of the current scene and save. + void saveScreenshot(const std::string &nameFile, bool jpg, bool png, bool tga); + + /// Load a mesh or particle system and add to current scene. + /// @param meshFileName - name loading shape or ps file. + /// @param skelFileName - name loading skeletin file. + /// @return true if file have been loaded, false if file have not been loaded. + bool loadMesh (const std::string &meshFileName, const std::string &skelFileName); + + /// Reset current scene. + void resetScene(); + + /// Update the navigation camera. + /// @param deltaPsi - delta angle horizontal (radians). + /// @param deltaPhi - delta angle vertical (radians). + /// @param deltaDist - delta distance. + void updateCamera(float deltaPsi, float deltaPhi, float deltaDist); + + /// Set the background color. + /// @param backgroundColor - background color. + void setBackgroundColor(NLMISC::CRGBA backgroundColor); + + /// Set type driver. + /// @param Direct3D - type driver (true - Direct3D) or (false -OpenGL) + void setGraphicsDriver(bool Direct3D); + + /// Set size viewport for correct set perspective + /// @param w - width window. + /// @param h - height window. + void setSizeViewport(uint16 w, uint16 h); + void getSizeViewport(float &left, float &right, float &bottom, float &top, float &znear, float &zfar); + + /// Select instance from the scene + /// @param name - name instance, "" if no instance edited + void setCurrentObject(const std::string &name); + + /// Get current instance from the scene + /// @return name current instance, "" if no instance edited + const std::string& getCurrentObject() { return _CurrentInstance; } + + /// Get entity from the scene + /// @return ref Entity + CEntity& getEntity(const std::string &name); + + /// Get full list instances from the scene + /// @param listObj - ref of return list instances + void getListObjects(std::vector &listObj); + + /// Get value background color. + /// @return background color. + NLMISC::CRGBA getBackgroundColor() { return _BackgroundColor; } + + /// Get type driver. + /// @return true if have used Direct3D driver, false OpenGL driver. + inline bool getDirect3D() { return _Direct3D; } + + /// Get a pointer to the driver. + /// @return pointer to the driver. + inline NL3D::UDriver *getDriver() { return _Driver; } + + /// Get a pointer to the scene. + /// @return pointer to the scene. + inline NL3D::UScene *getScene() { return _Scene; } + + /// Get a manager of playlist + /// @return pointer to the UPlayListManager + inline NL3D::UPlayListManager *getPlayListManager() { return _PlayListManager; } + +private: + void deleteEntity (CEntity &entity); + + /// Delete all entities + void deleteEntities(); + + /// Load background color from config file, intended for CConfiguration. + void cfcbBackgroundColor(NLMISC::CConfigFile::CVar &var); + void cfcbGraphicsDriver(NLMISC::CConfigFile::CVar &var); + + NLMISC::CRGBA _BackgroundColor; + + NL3D::UDriver *_Driver; + NL3D::UScene *_Scene; + NL3D::UPlayListManager *_PlayListManager; + NL3D::ULight *_Light; + NL3D::UCamera *_Camera; + NL3D::U3dMouseListener *_MouseListener; + + // The entities storage + CEntities _Entities; + + /// Camera parameters. + float _phi, _psi, _dist; + + bool _Direct3D; + + std::string _CurrentInstance; + + // a temporary solution, and later remove + friend class CAnimationSetDialog; +};/* class CObjectViewer */ + +} /* namespace NLQT */ + +#endif // OBJECT_VIEWER_H diff --git a/code/ryzom/tools/leveldesign/georges_editor_qt/src/objectviewer_dialog.cpp b/code/ryzom/tools/leveldesign/georges_editor_qt/src/objectviewer_dialog.cpp new file mode 100644 index 000000000..0fb8169ca --- /dev/null +++ b/code/ryzom/tools/leveldesign/georges_editor_qt/src/objectviewer_dialog.cpp @@ -0,0 +1,408 @@ +/* + Georges Editor Qt + Copyright (C) 2010 Adrian Jaekel + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . +*/ + +#include "objectviewer_dialog.h" + +// Qt includes +#include +#include +#include +#include +#include + +// NeL includes +#include +#include + +#include +#include +#include + +// Project includes +#include "modules.h" + +using namespace std; +using namespace NL3D; + +namespace NLQT { + +CObjectViewerDialog::CObjectViewerDialog(QWidget *parent) +: _isGraphicsInitialized(false), _isGraphicsEnabled(false), QDockWidget(parent) +{ + _ui.setupUi(this); + + //widget = new QWidget(dockWidgetContents); + //widget->setObjectName(QString::fromUtf8("widget")); + + + _nlw = new QNLWidget(_ui.dockWidgetContents); + _nlw->setObjectName(QString::fromUtf8("nlwidget")); + _ui.gridLayout->addWidget(_nlw, 0, 0, 1, 1); + //nlw->setLayout(new QGridLayout(nlw)); + //_ui.widget = nlw; + //QWidget * w = widget(); + + _isGraphicsEnabled = true; + + // As a special case, a QTimer with a timeout of 0 will time out as soon as all the events in the window system's event queue have been processed. + // This can be used to do heavy work while providing a snappy user interface. + _mainTimer = new QTimer(this); + connect(_mainTimer, SIGNAL(timeout()), this, SLOT(updateRender())); + // timer->start(); // <- timeout 0 + // it's heavy on cpu, though, when no 3d driver initialized :) + _mainTimer->start(5); // 25fps +} + +CObjectViewerDialog::~CObjectViewerDialog() { + _mainTimer->stop(); +} + +void CObjectViewerDialog::init() +{ + connect(this, SIGNAL(topLevelChanged(bool)), + this, SLOT(topLevelChanged(bool))); + //H_AUTO2 + nldebug("CObjectViewerDialog::init %d",_nlw->winId()); + +#ifdef NL_OS_UNIX + dynamic_cast(widget())->makeCurrent(); +#endif // NL_OS_UNIX + + Modules::objView().init((nlWindow)_nlw->winId(), 20, 20); + setMouseTracking(true); +} + +void CObjectViewerDialog::setVisible(bool visible) +{ + // called by show() + // code assuming visible window needed to init the 3d driver + if (visible != isVisible()) + { + if (visible) + { + QDockWidget::setVisible(true); + updateInitialization(true); + } + else + { + updateInitialization(false); + QDockWidget::setVisible(false); + } + } +} + +void CObjectViewerDialog::updateInitialization(bool visible) +{ + //nldebug("CMainWindow::updateInitialization"); + bool done; + do + { + done = true; // set false whenever change + bool wantGraphics = _isGraphicsEnabled && visible; + // bool wantLandscape = wantGraphics && m_IsGraphicsInitialized && isLandscapeEnabled; + + // .. stuff that depends on other stuff goes on top to prioritize deinitialization + + // Landscape + // ... + + // Graphics (Driver) + if (_isGraphicsInitialized) + { + if (!wantGraphics) + { + _isGraphicsInitialized = false; + release(); + _mainTimer->stop(); + done = false; + } + + } + else + { + if (wantGraphics) + { + init(); + _isGraphicsInitialized = true; + _mainTimer->start(5); + done = false; + } + } + + + + } while (!done); +} + +void CObjectViewerDialog::updateRender() +{ + //nldebug("CMainWindow::updateRender"); + updateInitialization(isVisible()); + + //QModelIndex index = _dirModel->setRootPath("D:/Dev/Ryzom/code/ryzom/common/data_leveldesign/leveldesign"); + //_dirTree->setRootIndex(index); + + if (isVisible()) + { + // call all update functions + // 01. Update Utilities (configuration etc) + + // 02. Update Time (deltas) + // ... + + // 03. Update Receive (network, servertime, receive messages) + // ... + + // 04. Update Input (keyboard controls, etc) + if (_isGraphicsInitialized) + Modules::objView().updateInput(); + + // 05. Update Weather (sky, snow, wind, fog, sun) + // ... + + // 06. Update Entities (movement, do after possible tp from incoming messages etc) + // - Move other entities + // - Update self entity + // - Move bullets + // ... + + // 07. Update Landscape (async zone loading near entity) + // ... + + // 08. Update Collisions (entities) + // - Update entities + // - Update move container (swap with Update entities? todo: check code!) + // - Update bullets + // ... + + // 09. Update Animations (playlists) + // - Needs to be either before or after entities, not sure, + // there was a problem with wrong order a while ago!!! + + + //Modules::objView().updateAnimation(_AnimationDialog->getTime()); + + // 10. Update Camera (depends on entities) + // ... + + // 11. Update Interface (login, ui, etc) + // ... + + // 12. Update Sound (sound driver) + // ... + + // 13. Update Send (network, send new position etc) + // ... + + // 14. Update Debug (stuff for dev) + // ... + + if (_isGraphicsInitialized && !Modules::objView().getDriver()->isLost()) + { + // 01. Render Driver (background color) + Modules::objView().renderDriver(); // clear all buffers + + // 02. Render Sky (sky scene) + // ... + + // 04. Render Scene (entity scene) + Modules::objView().renderScene(); + + // 05. Render Effects (flare) + // ... + + // 06. Render Interface 3D (player names) + // ... + + // 07. Render Debug 3D + // ... + + // 08. Render Interface 2D (chatboxes etc, optionally does have 3d) + // ... + + // 09. Render Debug 2D (stuff for dev) + Modules::objView().renderDebug2D(); + + // swap 3d buffers + Modules::objView().getDriver()->swapBuffers(); + } + } +} + +void CObjectViewerDialog::release() +{ + //H_AUTO2 + nldebug("CObjectViewerDialog::release"); + + Modules::objView().release(); +} + +void CObjectViewerDialog::reinit() +{ + //H_AUTO2 + nldebug("CObjectViewerDialog::reinit"); + + Modules::objView().release(); + //Modules::objView().reinit(_ui.frame->winId(), width(), height()); +} + +QAction *CObjectViewerDialog::createSaveScreenshotAction(QObject *parent) +{ + QAction *action = new QAction(parent); + connect(action, SIGNAL(triggered()), this, SLOT(saveScreenshot())); + return action; +} + +QAction *CObjectViewerDialog::createSetBackgroundColor(QObject *parent) +{ + QAction *action = new QAction(parent); + connect(action, SIGNAL(triggered()), this, SLOT(setBackgroundColor())); + return action; +} + +void CObjectViewerDialog::saveScreenshot() +{ + Modules::objView().saveScreenshot("screenshot", false, true, false); +} + +void CObjectViewerDialog::setBackgroundColor() +{ + QColor color = QColorDialog::getColor(QColor(Modules::objView().getBackgroundColor().R, + Modules::objView().getBackgroundColor().G, + Modules::objView().getBackgroundColor().B)); + Modules::objView().setBackgroundColor(NLMISC::CRGBA(color.red(), color.green(), color.blue())); +} + +void CObjectViewerDialog::topLevelChanged ( bool topLevel ) { + //nldebug("CObjectViewerDialog::topLevelChanged topLevel:%d",topLevel); + nldebug("CObjectViewerDialog::topLevelChanged winId:%d",winId()); + // winId changing when re/docking + //Modules::georges().init(); + Modules::objView().reinit((nlWindow)_nlw->winId(), _nlw->width(), _nlw->height()); +} + +void CObjectViewerDialog::resizeEvent(QResizeEvent *resizeEvent) +{ + QDockWidget::resizeEvent(resizeEvent); + if (Modules::objView().getDriver()) + Modules::objView().setSizeViewport(resizeEvent->size().width(), resizeEvent->size().height()); + + // The OpenGL driver does not resize automatically. + // The Direct3D driver breaks the window mode to include window borders when calling setMode windowed. + + // Resizing the window after switching drivers a few times becomes slow. + // There is probably something inside the drivers not being released properly. +} + +void CObjectViewerDialog::wheelEvent(QWheelEvent *event) +{ + //nldebug("CObjectViewerDialog::wheelEvent"); + // Get relative positions. + float fX = 1.0f - (float)event->pos().x() / this->width(); + float fY = 1.0f - (float)event->pos().y() / this->height(); + + // Set the buttons currently pressed. + NLMISC::TMouseButton buttons = (NLMISC::TMouseButton)getNelButtons(event); + if(event->delta() > 0) + Modules::objView().getDriver()->EventServer.postEvent(new NLMISC::CEventMouseWheel(-fX, fY, buttons, true, this)); + else + Modules::objView().getDriver()->EventServer.postEvent(new NLMISC::CEventMouseWheel(-fX, fY, buttons, false, this)); + +} + +uint32 CObjectViewerDialog::getNelButtons(QMouseEvent *event) { + //nldebug("CObjectViewerDialog::getNelButtons"); + uint32 buttons = NLMISC::noButton; + if(event->buttons() & Qt::LeftButton) buttons |= NLMISC::leftButton; + if(event->buttons() & Qt::RightButton) buttons |= NLMISC::rightButton; + if(event->buttons() & Qt::MidButton) buttons |= NLMISC::middleButton; + if(event->modifiers() & Qt::ControlModifier) buttons |= NLMISC::ctrlButton; + if(event->modifiers() & Qt::ShiftModifier) buttons |= NLMISC::shiftButton; + if(event->modifiers() & Qt::AltModifier) buttons |= NLMISC::altButton; + + return buttons; +} + +uint32 CObjectViewerDialog::getNelButtons(QWheelEvent *event) { + //nldebug("CObjectViewerDialog::getNelButtons"); + uint32 buttons = NLMISC::noButton; + if(event->buttons() & Qt::LeftButton) buttons |= NLMISC::leftButton; + if(event->buttons() & Qt::RightButton) buttons |= NLMISC::rightButton; + if(event->buttons() & Qt::MidButton) buttons |= NLMISC::middleButton; + if(event->modifiers() & Qt::ControlModifier) buttons |= NLMISC::ctrlButton; + if(event->modifiers() & Qt::ShiftModifier) buttons |= NLMISC::shiftButton; + if(event->modifiers() & Qt::AltModifier) buttons |= NLMISC::altButton; + + return buttons; +} + +void CObjectViewerDialog::mousePressEvent(QMouseEvent *event) { + //nldebug("CObjectViewerDialog::mousePressEvent"); + // Get relative positions. + float fX = 1.0f - (float)event->pos().x() / this->width(); + float fY = 1.0f - (float)event->pos().y() / this->height(); + + // Set the buttons currently pressed. + NLMISC::TMouseButton buttons = (NLMISC::TMouseButton)getNelButtons(event); + + if(event->button() == Qt::LeftButton) + Modules::objView().getDriver()->EventServer.postEvent( + new NLMISC::CEventMouseDown( -fX, fY, + (NLMISC::TMouseButton)(NLMISC::leftButton|(buttons&~(NLMISC::leftButton|NLMISC::middleButton|NLMISC::rightButton))), this)); + if(event->button() == Qt::MidButton) + Modules::objView().getDriver()->EventServer.postEvent( + new NLMISC::CEventMouseDown( -fX, fY, + (NLMISC::TMouseButton)(NLMISC::middleButton|(buttons&~(NLMISC::middleButton|NLMISC::leftButton|NLMISC::rightButton))), this)); + if(event->button() == Qt::RightButton) + Modules::objView().getDriver()->EventServer.postEvent( + new NLMISC::CEventMouseDown( -fX, fY, + (NLMISC::TMouseButton)(NLMISC::rightButton|(buttons&~(NLMISC::rightButton|NLMISC::leftButton|NLMISC::middleButton))), this)); +} + +void CObjectViewerDialog::mouseReleaseEvent(QMouseEvent *event) { + //nldebug("CObjectViewerDialog::mouseReleaseEvent"); + // Get relative positions. + float fX = 1.0f - (float)event->pos().x() / this->width(); + float fY = 1.0f - (float)event->pos().y() / this->height(); + + // Set the buttons currently pressed. + NLMISC::TMouseButton buttons = (NLMISC::TMouseButton)getNelButtons(event); + + if(event->button() == Qt::LeftButton) + Modules::objView().getDriver()->EventServer.postEvent( + new NLMISC::CEventMouseUp( -fX, fY, NLMISC::leftButton, this)); + if(event->button() == Qt::MidButton) + Modules::objView().getDriver()->EventServer.postEvent( + new NLMISC::CEventMouseUp( -fX, fY, NLMISC::middleButton, this)); + if(event->button() == Qt::RightButton) + Modules::objView().getDriver()->EventServer.postEvent( + new NLMISC::CEventMouseUp( -fX, fY, NLMISC::rightButton, this)); +} + +void CObjectViewerDialog::mouseMoveEvent(QMouseEvent *event) { + //nldebug("CObjectViewerDialog::mouseMoveEvent"); + // Get relative positions. + float fX = 1.0f - (float)event->pos().x() / this->width(); + float fY = 1.0f - (float)event->pos().y() / this->height(); + + if ((fX == 0.5f) && (fY == 0.5f)) return; + NLMISC::TMouseButton buttons = (NLMISC::TMouseButton)getNelButtons(event); + Modules::objView().getDriver()->EventServer.postEvent(new NLMISC::CEventMouseMove(-fX, fY, buttons, this)); +} + +} /* namespace NLQT */ diff --git a/code/ryzom/tools/leveldesign/georges_editor_qt/src/objectviewer_dialog.h b/code/ryzom/tools/leveldesign/georges_editor_qt/src/objectviewer_dialog.h new file mode 100644 index 000000000..eb80000ab --- /dev/null +++ b/code/ryzom/tools/leveldesign/georges_editor_qt/src/objectviewer_dialog.h @@ -0,0 +1,108 @@ +/* + Georges Editor Qt + Copyright (C) 2010 Adrian Jaekel + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . +*/ + +#ifndef OBJECTVIEWER_DIALOG_H +#define OBJECTVIEWER_DIALOG_H + +#include +#include + +#include "ui_objectviewer_form.h" + +// Qt includes +#include +#include +#include + +// STL includes + +// NeL includes +#include + +// Project includes + +#ifdef NL_OS_WINDOWS +//typedef QDockWidget QNLWidget; +typedef QWidget QNLWidget; +#else // NL_OS_UNIX +typedef QGLWidget QNLWidget; +#endif // NL_OS_UNIX + +class QAction; + +namespace NLQT { + +class CObjectViewerDialog: public QDockWidget, public NLMISC::IEventEmitter +{ + Q_OBJECT + +public: + CObjectViewerDialog(QWidget *parent = 0); + ~CObjectViewerDialog(); + + virtual void setVisible(bool visible); + // virtual QPaintEngine* paintEngine() const { return NULL; } + + void init(); + void release(); + void reinit(); + + QAction *createSaveScreenshotAction(QObject *parent); + QAction *createSetBackgroundColor(QObject *parent); + +private Q_SLOTS: + void updateRender(); + + void saveScreenshot(); + void setBackgroundColor(); + + void submitEvents(NLMISC::CEventServer &server, bool allWindows) { }; + void emulateMouseRawMode(bool) { }; + + void topLevelChanged(bool topLevel); + +protected: + virtual void resizeEvent(QResizeEvent *resizeEvent); + virtual void mousePressEvent(QMouseEvent *event); + virtual void mouseReleaseEvent(QMouseEvent *event); + virtual void wheelEvent(QWheelEvent *event); + virtual void mouseMoveEvent(QMouseEvent *event); + + uint32 getNelButtons(QMouseEvent *event); + uint32 getNelButtons(QWheelEvent *event); + +private: + CObjectViewerDialog(const CObjectViewerDialog &); + CObjectViewerDialog &operator=(const CObjectViewerDialog &); + + void updateInitialization(bool visible); + + Ui::CObjectViewerDialog _ui; + + // render stuff + QTimer *_mainTimer; + bool _isGraphicsInitialized, _isGraphicsEnabled; + + QNLWidget * _nlw; + + friend class CMainWindow; +}; /* CObjectViewerDialog */ + +} /* namespace NLQT */ + +#endif // OBJECTVIEWER_DIALOG_H diff --git a/code/ryzom/tools/leveldesign/georges_editor_qt/src/objectviewer_form.ui b/code/ryzom/tools/leveldesign/georges_editor_qt/src/objectviewer_form.ui new file mode 100644 index 000000000..fefe3f5b1 --- /dev/null +++ b/code/ryzom/tools/leveldesign/georges_editor_qt/src/objectviewer_form.ui @@ -0,0 +1,28 @@ + + + CObjectViewerDialog + + + + 0 + 0 + 352 + 286 + + + + + 80 + 50 + + + + 3D View + + + + + + + + diff --git a/code/ryzom/tools/leveldesign/georges_editor_qt/src/qt_displayer.cpp b/code/ryzom/tools/leveldesign/georges_editor_qt/src/qt_displayer.cpp new file mode 100644 index 000000000..0c49f3447 --- /dev/null +++ b/code/ryzom/tools/leveldesign/georges_editor_qt/src/qt_displayer.cpp @@ -0,0 +1,113 @@ +/* +Georges Editor Qt +Copyright (C) 2010 Adrian Jaekel + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program. If not, see . + +*/ + +// Nel includes + +#include "qt_displayer.h" +#include +#include +#include + +namespace NLQT { + + CQtDisplayer::CQtDisplayer(QPlainTextEdit *dlgDebug, bool eraseLastLog, const char *displayerName, bool raw) + : NLMISC::IDisplayer (displayerName), _NeedHeader(true), _LastLogSizeChecked(0), _Raw(raw) { + setParam(dlgDebug,eraseLastLog); + } + + CQtDisplayer::CQtDisplayer() : IDisplayer (""), _NeedHeader(true), _LastLogSizeChecked(0), _Raw(false) { + ; + } + + CQtDisplayer::~CQtDisplayer() { + ; + } + + void CQtDisplayer::setParam (QPlainTextEdit *dlgDebug, bool eraseLastLog) { + m_DlgDebug=dlgDebug; + //dlgDebug->dlgDbgText->WriteText("test"); + } + + void CQtDisplayer::doDisplay ( const NLMISC::CLog::TDisplayInfo& args, const char *message ) { + bool needSpace = false; + std::string str; + + if(m_DlgDebug==NULL) + return; + + QTextCharFormat format; + + if (args.Date != 0 && !_Raw) { + str += dateToHumanString(args.Date); + needSpace = true; + } + + if (args.LogType != NLMISC::CLog::LOG_NO && !_Raw) { + if (needSpace) { str += " "; needSpace = false; } + str += logTypeToString(args.LogType); + if (args.LogType == NLMISC::CLog::LOG_WARNING) + format.setForeground(QBrush(QColor("red"))); + else + format.setForeground(QBrush(QColor("black"))); + needSpace = true; + } + + // Write thread identifier + /*if ( args.ThreadId != 0 && !_Raw) { + if (needSpace) { str += " "; needSpace = false; } + str += NLMISC::toString(args.ThreadId); + needSpace = true; + }*/ + /*if (!args.ProcessName.empty() && !_Raw) { + if (needSpace) { str += " "; needSpace = false; } + str += args.ProcessName; + needSpace = true; + }*/ + + //if (args.FileName != NULL && !_Raw) { + // if (needSpace) { str += " "; needSpace = false; } + // str += NLMISC::CFile::getFilename(args.FileName); + // needSpace = true; + //} + + /*if (args.Line != -1 && !_Raw) { + if (needSpace) { str += " "; needSpace = false; } + str += NLMISC::toString(args.Line); + needSpace = true; + }*/ + + if (args.FuncName != NULL && !_Raw) { + if (needSpace) { str += " "; needSpace = false; } + str += args.FuncName; + needSpace = true; + } + + if (needSpace) { str += " : "; needSpace = false; } + str += message; + + + + m_DlgDebug->textCursor().insertText(str.c_str(), format); + //m_DlgDebug->setCenterOnScroll(true); + m_DlgDebug->centerCursor(); + //m_DlgDebug->ensureCursorVisible(); + + } + +} \ No newline at end of file diff --git a/code/ryzom/tools/leveldesign/georges_editor_qt/src/qt_displayer.h b/code/ryzom/tools/leveldesign/georges_editor_qt/src/qt_displayer.h new file mode 100644 index 000000000..baa4fd371 --- /dev/null +++ b/code/ryzom/tools/leveldesign/georges_editor_qt/src/qt_displayer.h @@ -0,0 +1,53 @@ +/* +Georges Editor Qt +Copyright (C) 2010 Adrian Jaekel + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program. If not, see . + +*/ + + +#ifndef QTDISPLAYER_H +#define QTDISPLAYER_H + +// NeL includes +#include "modules.h" +#include + +// Qt includes +#include + +namespace NLQT { + + class CQtDisplayer : virtual public NLMISC::IDisplayer + { + public: + CQtDisplayer(QPlainTextEdit *dlgDebug, bool eraseLastLog = false, const char *displayerName = "", bool raw = false); + CQtDisplayer(); + ~CQtDisplayer (); + void setParam (QPlainTextEdit *dlgDebug, bool eraseLastLog = false); + + protected: + virtual void doDisplay ( const NLMISC::CLog::TDisplayInfo& args, const char *message ); + + private: + QPlainTextEdit *m_DlgDebug; + bool _NeedHeader; + uint _LastLogSizeChecked; + bool _Raw; + };/* class CQtDisplayer */ + +} /* namespace NLQT */ + +#endif //QTDISPLAYER_H \ No newline at end of file diff --git a/code/ryzom/tools/leveldesign/georges_editor_qt/src/settings_dialog.cpp b/code/ryzom/tools/leveldesign/georges_editor_qt/src/settings_dialog.cpp new file mode 100644 index 000000000..483c78225 --- /dev/null +++ b/code/ryzom/tools/leveldesign/georges_editor_qt/src/settings_dialog.cpp @@ -0,0 +1,200 @@ +/* +Georges Editor Qt +Copyright (C) 2010 Adrian Jaekel + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program. If not, see . +*/ + +#include "settings_dialog.h" + +// Qt includes +#include +#include +#include + +// NeL includes +#include + +// Project includes +#include "modules.h" + +using namespace NLMISC; + +namespace NLQT { + + CSettingsDialog::CSettingsDialog(QWidget *parent) + : QDialog(parent) + { + ui.setupUi(this); + + // setup config file callbacks and initialize values + Modules::config().setAndCallback("GraphicsDrivers", CConfigCallback(this, &CSettingsDialog::cfcbGraphicsDrivers)); + Modules::config().setAndCallback("SearchPaths", CConfigCallback(this, &CSettingsDialog::cfcbSearchPaths)); + Modules::config().setAndCallback("LeveldesignPath", CConfigCallback(this, &CSettingsDialog::cfcbLeveldesignPath)); + + // load settings from the config file + + connect(ui.addToolButton, SIGNAL(clicked()), this, SLOT(addPath())); + connect(ui.removeToolButton, SIGNAL(clicked()), this, SLOT(removePath())); + connect(ui.upToolButton, SIGNAL(clicked()), this, SLOT(upPath())); + connect(ui.downToolButton, SIGNAL(clicked()), this, SLOT(downPath())); + connect(ui.buttonBox, SIGNAL(accepted()), this, SLOT(applyPressed())); + + connect(ui.browseLdPath, SIGNAL(clicked()), this, SLOT(browseLeveldesignPath())); + +#ifdef NL_OS_UNIX + ui.driverGraphComboBox->setEnabled(false); +#endif + + } + + CSettingsDialog::~CSettingsDialog() + { + Modules::config().dropCallback("GraphicsDrivers"); + Modules::config().dropCallback("SearchPaths"); + Modules::config().dropCallback("LeveldesignPath"); + } + + void CSettingsDialog::addPath() + { + QListWidgetItem *newItem = new QListWidgetItem; + QFileDialog dialog(this); + dialog.setOption(QFileDialog::ShowDirsOnly, true); + dialog.setFileMode(QFileDialog::Directory); + if (dialog.exec()) { + QString newPath = dialog.selectedFiles().first(); + if (!newPath.isEmpty()) + { + newItem->setText(newPath); + newItem->setFlags(Qt::ItemIsEditable | Qt::ItemIsEnabled | Qt::ItemIsSelectable); + ui.pathsListWidget->addItem(newItem); + } + } + } + + void CSettingsDialog::removePath() + { + QListWidgetItem *removeItem = ui.pathsListWidget->takeItem(ui.pathsListWidget->currentRow()); + if (!removeItem) delete removeItem; + } + + void CSettingsDialog::upPath() + { + sint currentRow = ui.pathsListWidget->currentRow(); + if (!(currentRow == 0)) + { + QListWidgetItem *item = ui.pathsListWidget->takeItem(currentRow); + ui.pathsListWidget->insertItem(--currentRow, item); + ui.pathsListWidget->setCurrentRow(currentRow); + } + } + + void CSettingsDialog::downPath() + { + sint currentRow = ui.pathsListWidget->currentRow(); + if (!(currentRow == ui.pathsListWidget->count()-1)) + { + QListWidgetItem *item = ui.pathsListWidget->takeItem(currentRow); + ui.pathsListWidget->insertItem(++currentRow, item); + ui.pathsListWidget->setCurrentRow(currentRow); + } + } + + void CSettingsDialog::applyPressed() + { + + // settings take after restart the program + /*QMessageBox::warning(this, tr("Settings"), + tr("Graphics and sound settings " + "take after restart the program"), + QMessageBox::Ok);*/ + + // save graphics settings to config file + Modules::config().getConfigFile().getVar("GraphicsDriver").setAsString(ui.driverGraphComboBox->currentText().toStdString()); + + // save leveldesign path to config file + std::string ldPath = ui.leveldesignPath->text().toStdString(); + Modules::config().getConfigFile().getVar("LeveldesignPath").forceAsString(ldPath); + Q_EMIT ldPathChanged(ldPath.c_str()); + + // save search paths to config file + std::vector list; + for (sint i = 0; i < ui.pathsListWidget->count(); ++i) + { + std::string str = ui.pathsListWidget->item(i)->text().toStdString(); + if (str != "") + list.push_back(str); + } + + if (list.empty()) { + Modules::config().getConfigFile().getVar("SearchPaths").forceAsString(""); + } else { + Modules::config().getConfigFile().getVar("SearchPaths").forceAsString(""); + Modules::config().getConfigFile().getVar("SearchPaths").setAsString(list); + } + + // save config file + Modules::config().getConfigFile().save(); + + // reload search paths + Modules::config().configSearchPaths(); + Modules::config().configLeveldesignPath(); + } + + void CSettingsDialog::cfcbGraphicsDrivers(NLMISC::CConfigFile::CVar &var) + { + while (ui.driverGraphComboBox->count()) + ui.driverGraphComboBox->removeItem(0); + + // load types graphics driver from the config file + for (uint i = 0; i < var.size(); ++i) + ui.driverGraphComboBox->addItem(var.asString(i).c_str()); + + // set graphics driver from the config file + QString value = Modules::config().getValue("GraphicsDriver",std::string("OpenGL")).c_str(); + QString dn = value.toLower(); + for (sint i = 0; i < ui.driverGraphComboBox->count(); ++i) + { + if (dn == ui.driverGraphComboBox->itemText(i).toLower()) + { + ui.driverGraphComboBox->setCurrentIndex(i); + return; + } + } + } + + void CSettingsDialog::cfcbSearchPaths(NLMISC::CConfigFile::CVar &var) + { + ui.pathsListWidget->clear(); + + // load search paths from the config file + for (uint i = 0; i < var.size(); ++i) + { + ui.pathsListWidget->addItem(var.asString(i).c_str()); + ui.pathsListWidget->item(i)->setFlags(Qt::ItemIsEditable | Qt::ItemIsEnabled | Qt::ItemIsSelectable); + } + } + + void CSettingsDialog::cfcbLeveldesignPath(NLMISC::CConfigFile::CVar &var) + { + // load leveldesign path from the config file + ui.leveldesignPath->setText(var.asString().c_str()); + } + + void CSettingsDialog::browseLeveldesignPath() + { + ui.leveldesignPath->setText(QFileDialog::getExistingDirectory(this, tr("Open Directory"), + QDir::currentPath(), QFileDialog::ShowDirsOnly | QFileDialog::DontResolveSymlinks)); + } +} /* namespace NLQT */ \ No newline at end of file diff --git a/code/ryzom/tools/leveldesign/georges_editor_qt/src/settings_dialog.h b/code/ryzom/tools/leveldesign/georges_editor_qt/src/settings_dialog.h new file mode 100644 index 000000000..f894219b6 --- /dev/null +++ b/code/ryzom/tools/leveldesign/georges_editor_qt/src/settings_dialog.h @@ -0,0 +1,65 @@ +/* + Georges Editor Qt + Copyright (C) 2010 Adrian Jaekel + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . +*/ + +#ifndef SETTINGS_DIALOG_H +#define SETTINGS_DIALOG_H + +#include +#include "ui_settings_form.h" + +// STL includes + +// NeL includes +#include + +// Project includes + +namespace NLQT { + +class CSettingsDialog: public QDialog +{ + Q_OBJECT + +public: + CSettingsDialog(QWidget *parent = 0); + ~CSettingsDialog(); + +Q_SIGNALS: + void ldPathChanged(QString); + +private Q_SLOTS: + void addPath(); + void removePath(); + void upPath(); + void downPath(); + void applyPressed(); + void browseLeveldesignPath(); + +private: + void cfcbGraphicsDrivers(NLMISC::CConfigFile::CVar &var); + void cfcbSoundDrivers(NLMISC::CConfigFile::CVar &var); + void cfcbSearchPaths(NLMISC::CConfigFile::CVar &var); + void cfcbLeveldesignPath(NLMISC::CConfigFile::CVar &var); + + Ui::CSettingsDialog ui; + +}; /* class CSettingsDialog */ + +} /* namespace NLQT */ + +#endif // SETTINGS_DIALOG_H diff --git a/code/ryzom/tools/leveldesign/georges_editor_qt/src/settings_form.ui b/code/ryzom/tools/leveldesign/georges_editor_qt/src/settings_form.ui new file mode 100644 index 000000000..064f8bcfe --- /dev/null +++ b/code/ryzom/tools/leveldesign/georges_editor_qt/src/settings_form.ui @@ -0,0 +1,227 @@ + + + CSettingsDialog + + + Qt::NonModal + + + + 0 + 0 + 496 + 400 + + + + Settings + + + + :/images/preferences.png:/images/preferences.png + + + true + + + + + + Qt::Horizontal + + + QDialogButtonBox::Cancel|QDialogButtonBox::Ok + + + + + + + Graphics settings + + + + + + Driver + + + + + + + + 0 + 0 + + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + + + Search paths (shapes, textures etc.) + + + + + + + + + + + + 0 + 0 + + + + ... + + + + :/images/list-add.png:/images/list-add.png + + + + 16 + 16 + + + + + + + + ... + + + + :/images/list-remove.png:/images/list-remove.png + + + + + + + ... + + + + :/images/go-up.png:/images/go-up.png + + + + + + + ... + + + + :/images/go-down.png:/images/go-down.png + + + + + + + + + Qt::Vertical + + + + 20 + 195 + + + + + + + + + + + Leveldesign path + + + + + + ... + + + + + + + + + + + + + pathsListWidget + addToolButton + removeToolButton + upToolButton + downToolButton + buttonBox + + + + + + + buttonBox + accepted() + CSettingsDialog + accept() + + + 222 + 385 + + + 157 + 274 + + + + + buttonBox + rejected() + CSettingsDialog + reject() + + + 290 + 391 + + + 286 + 274 + + + + + diff --git a/code/ryzom/tools/leveldesign/georges_editor_qt/src/spindelegate.cpp b/code/ryzom/tools/leveldesign/georges_editor_qt/src/spindelegate.cpp new file mode 100644 index 000000000..73106745e --- /dev/null +++ b/code/ryzom/tools/leveldesign/georges_editor_qt/src/spindelegate.cpp @@ -0,0 +1,275 @@ +/* + Georges Editor Qt + Copyright (C) 2010 Adrian Jaekel + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . +*/ + +#include "spindelegate.h" + +// NeL includes +#include +#include +#include + +// Qt includes +#include +#include +#include +#include +#include +#include +#include +#include +#include +// Project includes +#include "georgesform_model.h" +#include "formitem.h" + +namespace NLQT { + + SpinBoxDelegate::SpinBoxDelegate(QObject *parent) + : QStyledItemDelegate(parent) + { + } + + QWidget *SpinBoxDelegate::createEditor(QWidget *parent, + const QStyleOptionViewItem & option , + const QModelIndex &index) const + { + CFormItem *item = static_cast(index.internalPointer()); + QString value = item->data(1).toString(); + + if (value.isEmpty()) + return 0; + + const NLGEORGES::UType *type = qobject_cast(index.model())-> + getItem(index)->getFormElm()->getType(); + if(type) { + int numDefinitions = type->getNumDefinition(); + + if (numDefinitions) { + std::string l, v; + QString label,value; + + QComboBox *editor = new QComboBox(parent); + for (int i = 0; i < numDefinitions; i++) { + type->getDefinition(i,l,v); + label = l.c_str(); + value = v.c_str(); + editor->addItem(label); + } + return editor; + } else { + switch (type->getType()) { + case NLGEORGES::UType::UnsignedInt: + case NLGEORGES::UType::SignedInt: + { + QSpinBox *editor = new QSpinBox(parent); + + //QString min = QString(type->getMin().c_str()); + //QString max = QString(type->getMax().c_str()); + //QString inc = QString(type->getIncrement().c_str()); + //nldebug(QString("min %1 max %2 inc %3").arg(min).arg(max).arg(inc).toStdString().c_str()); + + // TODO: use saved min/max values + editor->setMinimum(-99999); + editor->setMaximum(99999); + editor->setSingleStep(1); + return editor; + } + case NLGEORGES::UType::Double: + { + QDoubleSpinBox *editor = new QDoubleSpinBox(parent); + + //QString min = QString(type->getMin().c_str()); + //QString max = QString(type->getMax().c_str()); + //QString inc = QString(type->getIncrement().c_str()); + //nldebug(QString("min %1 max %2 inc %3").arg(min).arg(max).arg(inc).toStdString().c_str()); + + // TODO: use saved min/max values + editor->setMinimum(-99999); + editor->setMaximum(99999); + editor->setSingleStep(0.1); + editor->setDecimals(1); + return editor; + } + case NLGEORGES::UType::Color: + { + return new QColorDialog(); + } + default: // UType::String + { + QLineEdit *editor = new QLineEdit(parent); + return editor; + } + } + } + } + return 0; + } + + void SpinBoxDelegate::setEditorData(QWidget *editor, + const QModelIndex &index) const + { + const NLGEORGES::UType *type = qobject_cast(index.model())-> + getItem(index)->getFormElm()->getType(); + int numDefinitions = type->getNumDefinition(); + QString value = index.model()->data(index, Qt::DisplayRole).toString(); + + if (numDefinitions) { + QComboBox *cb = static_cast(editor); + cb->setCurrentIndex(cb->findText(value)); + //cb->setIconSize() + } else { + switch (type->getType()) { + case NLGEORGES::UType::UnsignedInt: + case NLGEORGES::UType::SignedInt: + { + QSpinBox *spinBox = static_cast(editor); + spinBox->setValue((int)value.toDouble()); + break; + } + case NLGEORGES::UType::Double: + { + QDoubleSpinBox *spinBox = static_cast(editor); + spinBox->setValue(value.toDouble()); + break; + } + case NLGEORGES::UType::Color: + { + break; + } + default: + { + QLineEdit *textEdit = static_cast(editor); + textEdit->setText(value); + break; + } + } + } + } + + void SpinBoxDelegate::setModelData(QWidget *editor, QAbstractItemModel *model, + const QModelIndex &index) const + { + const NLGEORGES::UType *type = qobject_cast(index.model())-> + getItem(index)->getFormElm()->getType(); + int numDefinitions = type->getNumDefinition(); + + if (numDefinitions) { + QComboBox *comboBox = static_cast(editor); + QString value = comboBox->currentText(); + QString oldValue = index.model()->data(index, Qt::DisplayRole).toString(); + if (value == oldValue) { + // nothing's changed + } else { + nldebug(QString("setModelData from %1 to %2") + .arg(oldValue).arg(value).toStdString().c_str()); + model->setData(index, value, Qt::EditRole); + } + } else { + switch (type->getType()) { + case NLGEORGES::UType::UnsignedInt: + case NLGEORGES::UType::SignedInt: + { + QSpinBox *spinBox = static_cast(editor); + int value = spinBox->value(); + QString oldValue = index.model()->data(index, Qt::DisplayRole).toString(); + if (QString("%1").arg(value) == oldValue) { + // nothing's changed + } else { + nldebug(QString("setModelData from %1 to %2") + .arg(oldValue).arg(value).toStdString().c_str()); + model->setData(index, value, Qt::EditRole); + } + break; + } + case NLGEORGES::UType::Double: + { + QDoubleSpinBox *spinBox = static_cast(editor); + double value = spinBox->value(); + QString oldValue = index.model()->data(index, Qt::DisplayRole).toString(); + if (QString("%1").arg(value) == oldValue) { + // nothing's changed + } else { + nldebug(QString("setModelData from %1 to %2") + .arg(oldValue).arg(value).toStdString().c_str()); + model->setData(index, value, Qt::EditRole); + } + break; + } + case NLGEORGES::UType::Color: + { + break; // TODO + } + default: // UType::String + { + QLineEdit *textEdit = static_cast(editor); + QString value = textEdit->text(); + QString oldValue = index.model()->data(index, Qt::DisplayRole).toString(); + if (value == oldValue) { + // nothing's changed + } else { + nldebug(QString("setModelData from %1 to %2") + .arg(oldValue).arg(value).toStdString().c_str()); + model->setData(index, value, Qt::EditRole); + } + break; + } + } + } + } + + void SpinBoxDelegate::updateEditorGeometry(QWidget *editor, + const QStyleOptionViewItem &option, const QModelIndex &index) const + { + QRect r = option.rect; + editor->setGeometry(r); + //option.decorationAlignment = QStyleOptionViewItem::Right; + } + + void SpinBoxDelegate::paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const +{ + QStyleOptionViewItemV4 optionV4 = option; + optionV4.decorationPosition = QStyleOptionViewItem::Right; + //optionV4.decorationSize = QSize(32,32); + initStyleOption(&optionV4, index); + + QStyledItemDelegate::paint(painter,optionV4,index); + + //QStyle *style = optionV4.widget? optionV4.widget->style() : QApplication::style(); + + //QTextDocument doc; + //doc.setHtml(optionV4.text); + + ///// Painting item without text + //optionV4.text = QString(); + //style->drawControl(QStyle::CE_ItemViewItem, &optionV4, painter); + + //QAbstractTextDocumentLayout::PaintContext ctx; + + //// Highlighting text if item is selected + //if (optionV4.state & QStyle::State_Selected) + // ctx.palette.setColor(QPalette::Text, optionV4.palette.color(QPalette::Active, QPalette::HighlightedText)); + + //QRect textRect = style->subElementRect(QStyle::SE_ItemViewItemText, &optionV4); + //painter->save(); + //painter->translate(textRect.topLeft()); + //painter->setClipRect(textRect.translated(-textRect.topLeft())); + //doc.documentLayout()->draw(painter, ctx); + //painter->restore(); +} + +} diff --git a/code/ryzom/tools/leveldesign/georges_editor_qt/src/spindelegate.h b/code/ryzom/tools/leveldesign/georges_editor_qt/src/spindelegate.h new file mode 100644 index 000000000..907755018 --- /dev/null +++ b/code/ryzom/tools/leveldesign/georges_editor_qt/src/spindelegate.h @@ -0,0 +1,44 @@ +/* + Georges Editor Qt + Copyright (C) 2010 Adrian Jaekel + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . +*/ + +#ifndef DELEGATE_H +#define DELEGATE_H + +#include + +namespace NLQT { + + class SpinBoxDelegate : public QStyledItemDelegate +{ + +public: + SpinBoxDelegate(QObject *parent = 0); + + QWidget *createEditor(QWidget *parent, const QStyleOptionViewItem &option, + const QModelIndex &index) const; + void setEditorData(QWidget *editor, const QModelIndex &index) const; + void setModelData(QWidget *editor, QAbstractItemModel *model, + const QModelIndex &index) const; + void updateEditorGeometry(QWidget *editor, + const QStyleOptionViewItem &option, const QModelIndex &index) const; + void paint ( QPainter * painter, const QStyleOptionViewItem & option, + const QModelIndex & index ) const; +}; + +} +#endif diff --git a/code/ryzom/tools/leveldesign/georges_editor_qt/src/stdpch.cpp b/code/ryzom/tools/leveldesign/georges_editor_qt/src/stdpch.cpp new file mode 100644 index 000000000..f555cbb32 --- /dev/null +++ b/code/ryzom/tools/leveldesign/georges_editor_qt/src/stdpch.cpp @@ -0,0 +1,19 @@ +/* + Georges Editor Qt + Copyright (C) 2010 Adrian Jaekel + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . +*/ + +#include "stdpch.h" diff --git a/code/ryzom/tools/leveldesign/georges_editor_qt/src/stdpch.h b/code/ryzom/tools/leveldesign/georges_editor_qt/src/stdpch.h new file mode 100644 index 000000000..0ef614792 --- /dev/null +++ b/code/ryzom/tools/leveldesign/georges_editor_qt/src/stdpch.h @@ -0,0 +1,33 @@ +/* + Object Viewer Qt + Copyright (C) 2010 Dzmitry Kamiahin + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + +*/ + +#ifndef NL_STDPCH_H +#define NL_STDPCH_H + +#include + +#include +#include +#include +#include +#include + +#include + +#endif