├── .gitignore ├── CMakeLists.txt ├── LICENSE ├── README.md ├── main.cpp ├── mainwindow.cpp ├── mainwindow.h ├── mainwindow.ui ├── src ├── AnimTimeline │ ├── AnimTimelineSession.cpp │ ├── AnimTimelineSession.h │ ├── FormAnimTimeline.cpp │ ├── FormAnimTimeline.h │ ├── FormAnimTimeline.ui │ ├── QWidgetSlider.cpp │ ├── QWidgetSlider.h │ ├── configurations.h │ ├── images │ │ ├── deleteKey.png │ │ ├── deleteKey.xcf │ │ ├── end.png │ │ ├── end.xcf │ │ ├── forward.png │ │ ├── forward.xcf │ │ ├── help.png │ │ ├── help.xcf │ │ ├── key.png │ │ ├── key.xcf │ │ ├── leftSlider.png │ │ ├── less.png │ │ ├── less.xcf │ │ ├── pause.png │ │ ├── pause.xcf │ │ ├── play.png │ │ ├── play.xcf │ │ ├── plus.png │ │ ├── plus.xcf │ │ ├── rearward.png │ │ ├── rearward.xcf │ │ ├── rightSlider.png │ │ ├── start.png │ │ └── start.xcf │ ├── qdoublespinboxsmart.cpp │ ├── qdoublespinboxsmart.h │ ├── qframebuttons.cpp │ ├── qframebuttons.h │ ├── qframeselector.cpp │ ├── qframeselector.h │ ├── qframetimescale.cpp │ ├── qframetimescale.h │ ├── qscrollarearuler.cpp │ ├── qscrollarearuler.h │ ├── qspinboxsmart.cpp │ ├── qspinboxsmart.h │ ├── qtoolbuttonplaypause.cpp │ ├── qtoolbuttonplaypause.h │ ├── qwidgetruler.cpp │ ├── qwidgetruler.h │ └── timeline.qrc └── CMakeLists.txt ├── testApplication.png └── timeline.png /.gitignore: -------------------------------------------------------------------------------- 1 | # C++ objects and libs 2 | *.slo 3 | *.lo 4 | *.o 5 | *.a 6 | *.la 7 | *.lai 8 | *.so 9 | *.dll 10 | *.dylib 11 | 12 | # Qt-es 13 | object_script.*.Release 14 | object_script.*.Debug 15 | *_plugin_import.cpp 16 | /.qmake.cache 17 | /.qmake.stash 18 | *.pro.user 19 | *.pro.user.* 20 | *.qbs.user 21 | *.qbs.user.* 22 | *.moc 23 | moc_*.cpp 24 | moc_*.h 25 | qrc_*.cpp 26 | ui_*.h 27 | *.qmlc 28 | *.jsc 29 | Makefile* 30 | *build-* 31 | 32 | build 33 | 34 | # Qt unit tests 35 | target_wrapper.* 36 | 37 | # QtCreator 38 | *.autosave 39 | 40 | # QtCreator Qml 41 | *.qmlproject.user 42 | *.qmlproject.user.* 43 | 44 | # QtCreator CMake 45 | CMakeLists.txt.user* 46 | -------------------------------------------------------------------------------- /CMakeLists.txt: -------------------------------------------------------------------------------- 1 | CMAKE_MINIMUM_REQUIRED( VERSION 3.8 ) 2 | PROJECT(TestAnimTimeline) 3 | 4 | ################################################################################ 5 | # Compiler and linker options 6 | SET(CMAKE_AUTOMOC ON) 7 | SET(CMAKE_AUTORCC ON) 8 | SET(CMAKE_AUTOUIC ON) 9 | #SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11") 10 | 11 | ################################################################################ 12 | # Sources and headers 13 | #FIND_PACKAGE(Qt5 COMPONENTS Core Widgets REQUIRED) 14 | find_package(Qt5 COMPONENTS Core Widgets REQUIRED) 15 | 16 | FILE(GLOB headers *.h) 17 | FILE(GLOB sources *.cpp) 18 | 19 | file(GLOB forms *.ui) 20 | #qt5_wrap_ui(app_uis_moc ${app_uis}) 21 | 22 | #add_definitions(${Qt5Core_DEFINITIONS}) 23 | #add_definitions(${Qt5Widges_DEFINITIONS}) 24 | 25 | #INCLUDE_DIRECTORIES(${CMAKE_CURRENT_BINARY_DIR} ${CMAKE_CURRENT_SOURCE_DIR} 26 | include_directories( 27 | # src/ 28 | ${M_ANIM_TIMELINE_DIR} 29 | # src/AnimTimeline/ #for ui include "ui_animtimeline.h", moc not visible 30 | # ${CMAKE_CURRENT_BINARY_DIR} 31 | # ${CMAKE_CURRENT_SOURCE_DIR} 32 | ) 33 | 34 | #add_definitions( ${Qt5Core_DEFINITIONS} ) 35 | #add_definitions( ${Qt5Widges_DEFINITIONS} ) 36 | 37 | add_executable(${PROJECT_NAME} 38 | ${sources} 39 | ${forms} 40 | ${headers} 41 | ) 42 | 43 | target_link_libraries(${PROJECT_NAME} ${M_Qt5_LIBRARIES} AnimTimeline) 44 | ################################################################################ 45 | # Compile target 46 | #ADD_EXECUTABLE(${PROJECT_NAME} ${V1_SOURCE_FILES} ${V1_HEADER_FILES} ${CMAKE_CURRENT_SOURCE_DIR}/resource/timeline.qrc) 47 | #ADD_EXECUTABLE(${PROJECT_NAME} ${sources} ${headers} ${app_uis} src/AnimTimeline/timeline.qrc) 48 | # https://www.kdab.com/using-cmake-with-qt-5/ 49 | #qt5_use_modules(${PROJECT_NAME} Core Widgets) 50 | 51 | #add_definitions(-DQT_NO_DEBUG_OUTPUT) 52 | #if(CMAKE_BUILD_TYPE MATCHES "Release") 53 | # add_definitions(-DQT_NO_DEBUG_OUTPUT) 54 | #endif() 55 | 56 | add_subdirectory(src) 57 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Apache License 2 | Version 2.0, January 2004 3 | http://www.apache.org/licenses/ 4 | 5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 6 | 7 | 1. Definitions. 8 | 9 | "License" shall mean the terms and conditions for use, reproduction, 10 | and distribution as defined by Sections 1 through 9 of this document. 11 | 12 | "Licensor" shall mean the copyright owner or entity authorized by 13 | the copyright owner that is granting the License. 14 | 15 | "Legal Entity" shall mean the union of the acting entity and all 16 | other entities that control, are controlled by, or are under common 17 | control with that entity. For the purposes of this definition, 18 | "control" means (i) the power, direct or indirect, to cause the 19 | direction or management of such entity, whether by contract or 20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 21 | outstanding shares, or (iii) beneficial ownership of such entity. 22 | 23 | "You" (or "Your") shall mean an individual or Legal Entity 24 | exercising permissions granted by this License. 25 | 26 | "Source" form shall mean the preferred form for making modifications, 27 | including but not limited to software source code, documentation 28 | source, and configuration files. 29 | 30 | "Object" form shall mean any form resulting from mechanical 31 | transformation or translation of a Source form, including but 32 | not limited to compiled object code, generated documentation, 33 | and conversions to other media types. 34 | 35 | "Work" shall mean the work of authorship, whether in Source or 36 | Object form, made available under the License, as indicated by a 37 | copyright notice that is included in or attached to the work 38 | (an example is provided in the Appendix below). 39 | 40 | "Derivative Works" shall mean any work, whether in Source or Object 41 | form, that is based on (or derived from) the Work and for which the 42 | editorial revisions, annotations, elaborations, or other modifications 43 | represent, as a whole, an original work of authorship. For the purposes 44 | of this License, Derivative Works shall not include works that remain 45 | separable from, or merely link (or bind by name) to the interfaces of, 46 | the Work and Derivative Works thereof. 47 | 48 | "Contribution" shall mean any work of authorship, including 49 | the original version of the Work and any modifications or additions 50 | to that Work or Derivative Works thereof, that is intentionally 51 | submitted to Licensor for inclusion in the Work by the copyright owner 52 | or by an individual or Legal Entity authorized to submit on behalf of 53 | the copyright owner. For the purposes of this definition, "submitted" 54 | means any form of electronic, verbal, or written communication sent 55 | to the Licensor or its representatives, including but not limited to 56 | communication on electronic mailing lists, source code control systems, 57 | and issue tracking systems that are managed by, or on behalf of, the 58 | Licensor for the purpose of discussing and improving the Work, but 59 | excluding communication that is conspicuously marked or otherwise 60 | designated in writing by the copyright owner as "Not a Contribution." 61 | 62 | "Contributor" shall mean Licensor and any individual or Legal Entity 63 | on behalf of whom a Contribution has been received by Licensor and 64 | subsequently incorporated within the Work. 65 | 66 | 2. Grant of Copyright License. Subject to the terms and conditions of 67 | this License, each Contributor hereby grants to You a perpetual, 68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 69 | copyright license to reproduce, prepare Derivative Works of, 70 | publicly display, publicly perform, sublicense, and distribute the 71 | Work and such Derivative Works in Source or Object form. 72 | 73 | 3. Grant of Patent License. Subject to the terms and conditions of 74 | this License, each Contributor hereby grants to You a perpetual, 75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 76 | (except as stated in this section) patent license to make, have made, 77 | use, offer to sell, sell, import, and otherwise transfer the Work, 78 | where such license applies only to those patent claims licensable 79 | by such Contributor that are necessarily infringed by their 80 | Contribution(s) alone or by combination of their Contribution(s) 81 | with the Work to which such Contribution(s) was submitted. If You 82 | institute patent litigation against any entity (including a 83 | cross-claim or counterclaim in a lawsuit) alleging that the Work 84 | or a Contribution incorporated within the Work constitutes direct 85 | or contributory patent infringement, then any patent licenses 86 | granted to You under this License for that Work shall terminate 87 | as of the date such litigation is filed. 88 | 89 | 4. Redistribution. You may reproduce and distribute copies of the 90 | Work or Derivative Works thereof in any medium, with or without 91 | modifications, and in Source or Object form, provided that You 92 | meet the following conditions: 93 | 94 | (a) You must give any other recipients of the Work or 95 | Derivative Works a copy of this License; and 96 | 97 | (b) You must cause any modified files to carry prominent notices 98 | stating that You changed the files; and 99 | 100 | (c) You must retain, in the Source form of any Derivative Works 101 | that You distribute, all copyright, patent, trademark, and 102 | attribution notices from the Source form of the Work, 103 | excluding those notices that do not pertain to any part of 104 | the Derivative Works; and 105 | 106 | (d) If the Work includes a "NOTICE" text file as part of its 107 | distribution, then any Derivative Works that You distribute must 108 | include a readable copy of the attribution notices contained 109 | within such NOTICE file, excluding those notices that do not 110 | pertain to any part of the Derivative Works, in at least one 111 | of the following places: within a NOTICE text file distributed 112 | as part of the Derivative Works; within the Source form or 113 | documentation, if provided along with the Derivative Works; or, 114 | within a display generated by the Derivative Works, if and 115 | wherever such third-party notices normally appear. The contents 116 | of the NOTICE file are for informational purposes only and 117 | do not modify the License. You may add Your own attribution 118 | notices within Derivative Works that You distribute, alongside 119 | or as an addendum to the NOTICE text from the Work, provided 120 | that such additional attribution notices cannot be construed 121 | as modifying the License. 122 | 123 | You may add Your own copyright statement to Your modifications and 124 | may provide additional or different license terms and conditions 125 | for use, reproduction, or distribution of Your modifications, or 126 | for any such Derivative Works as a whole, provided Your use, 127 | reproduction, and distribution of the Work otherwise complies with 128 | the conditions stated in this License. 129 | 130 | 5. Submission of Contributions. Unless You explicitly state otherwise, 131 | any Contribution intentionally submitted for inclusion in the Work 132 | by You to the Licensor shall be under the terms and conditions of 133 | this License, without any additional terms or conditions. 134 | Notwithstanding the above, nothing herein shall supersede or modify 135 | the terms of any separate license agreement you may have executed 136 | with Licensor regarding such Contributions. 137 | 138 | 6. Trademarks. This License does not grant permission to use the trade 139 | names, trademarks, service marks, or product names of the Licensor, 140 | except as required for reasonable and customary use in describing the 141 | origin of the Work and reproducing the content of the NOTICE file. 142 | 143 | 7. Disclaimer of Warranty. Unless required by applicable law or 144 | agreed to in writing, Licensor provides the Work (and each 145 | Contributor provides its Contributions) on an "AS IS" BASIS, 146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 147 | implied, including, without limitation, any warranties or conditions 148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 149 | PARTICULAR PURPOSE. You are solely responsible for determining the 150 | appropriateness of using or redistributing the Work and assume any 151 | risks associated with Your exercise of permissions under this License. 152 | 153 | 8. Limitation of Liability. In no event and under no legal theory, 154 | whether in tort (including negligence), contract, or otherwise, 155 | unless required by applicable law (such as deliberate and grossly 156 | negligent acts) or agreed to in writing, shall any Contributor be 157 | liable to You for damages, including any direct, indirect, special, 158 | incidental, or consequential damages of any character arising as a 159 | result of this License or out of the use or inability to use the 160 | Work (including but not limited to damages for loss of goodwill, 161 | work stoppage, computer failure or malfunction, or any and all 162 | other commercial damages or losses), even if such Contributor 163 | has been advised of the possibility of such damages. 164 | 165 | 9. Accepting Warranty or Additional Liability. While redistributing 166 | the Work or Derivative Works thereof, You may choose to offer, 167 | and charge a fee for, acceptance of support, warranty, indemnity, 168 | or other liability obligations and/or rights consistent with this 169 | License. However, in accepting such obligations, You may act only 170 | on Your own behalf and on Your sole responsibility, not on behalf 171 | of any other Contributor, and only if You agree to indemnify, 172 | defend, and hold each Contributor harmless for any liability 173 | incurred by, or claims asserted against, such Contributor by reason 174 | of your accepting any such warranty or additional liability. 175 | 176 | END OF TERMS AND CONDITIONS 177 | 178 | APPENDIX: How to apply the Apache License to your work. 179 | 180 | To apply the Apache License to your work, attach the following 181 | boilerplate notice, with the fields enclosed by brackets "[]" 182 | replaced with your own identifying information. (Don't include 183 | the brackets!) The text should be enclosed in the appropriate 184 | comment syntax for the file format. We also recommend that a 185 | file or class name and description of purpose be included on the 186 | same "printed page" as the copyright notice for easier 187 | identification within third-party archives. 188 | 189 | Copyright [yyyy] [name of copyright owner] 190 | 191 | Licensed under the Apache License, Version 2.0 (the "License"); 192 | you may not use this file except in compliance with the License. 193 | You may obtain a copy of the License at 194 | 195 | http://www.apache.org/licenses/LICENSE-2.0 196 | 197 | Unless required by applicable law or agreed to in writing, software 198 | distributed under the License is distributed on an "AS IS" BASIS, 199 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 200 | See the License for the specific language governing permissions and 201 | limitations under the License. 202 | 203 | 204 | Property of University Paul Sabatier Toulouse 205 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # AnimTimeline 2 | Custom Qt widget like Blender timeline for animation 3 | 4 | ![timeline](timeline.png) 5 | 6 | Released date : April 2019 7 | 8 | ## Build Instructions (Linux) 9 | ```bash 10 | $ mkdir build 11 | $ cd build 12 | $ cmake .. 13 | $ make 14 | ``` 15 | 16 | ## Run test application 17 | ```viml 18 | ./build/AnimTimeline 19 | ``` 20 | 21 | [![test timeline](testApplication.png)](https://youtu.be/0igq4E6YkDE "wiew on youtube") 22 | 23 | 24 | ## On your Qt application write 25 | ```c++ 26 | AnimTimeline * timeline = new AnimTimeline(); 27 | timeline->show(); // dialog window 28 | ``` 29 | 30 | -------------------------------------------------------------------------------- /main.cpp: -------------------------------------------------------------------------------- 1 | #include "mainwindow.h" 2 | #include 3 | 4 | int main(int argc, char *argv[]) 5 | { 6 | QApplication a(argc, argv); 7 | MainWindow w; 8 | w.show(); 9 | 10 | return a.exec(); 11 | } 12 | -------------------------------------------------------------------------------- /mainwindow.cpp: -------------------------------------------------------------------------------- 1 | #include "mainwindow.h" 2 | #include "ui_mainwindow.h" 3 | 4 | #include 5 | //#include "animtimeline.h" 6 | //#include "dialog.h" 7 | #include 8 | #include 9 | 10 | 11 | MainWindow::MainWindow(QWidget *parent) : 12 | QMainWindow(parent), 13 | ui(new Ui::MainWindow) 14 | { 15 | ui->setupUi(this); 16 | 17 | // ui->widget->onChangeDuration(40); 18 | // ui->widget->onChangeCursor(5); 19 | // ui->widget->hide(); 20 | // ui->widget->setVisible(false); 21 | // ui->widget->setEnabled(false); 22 | // ui->widget->show(); 23 | 24 | 25 | // dialog->setModal(true); 26 | // dialog->exec(); 27 | 28 | // timeline = new AnimTimeline(this); 29 | // dialog = new Dialog(this); 30 | // dialog->show(); 31 | // timeline = new AnimTimelineWithSession(); 32 | // session = new AnimSession(timeline); 33 | // session->setAnimType(); 34 | // timeline->show(); 35 | // timeline->resize(100, 100); 36 | // signals 37 | // connect(timeline, &AnimTimeline::cursorChanged, ui->cursorIn, &QDoubleSpinBox::setValue); 38 | 39 | // --------------------------- ANIM_TIMELINE SIGNALS ---------------------- 40 | connect(ui->widget_timeline, SIGNAL(playClicked()), this, SLOT(onPlay())); 41 | connect(ui->widget_timeline, SIGNAL(pauseClicked()), this, SLOT(onPause())); 42 | // connect(timeline, SIGNAL(durationChanged(double)), ui->durationIn, SLOT(setValue(double))); 43 | connect(ui->widget_timeline, SIGNAL(durationChanged(double)), this, SLOT(onChangeDuration(double))); 44 | 45 | // connect(timeline, SIGNAL(durationChanged(double)), this, SLOT(onChangeDuration(double))); 46 | 47 | // connect(timeline, SIGNAL(cursorChanged(double)), ui->cursorIn, SLOT(setValue(double))); 48 | connect(ui->widget_timeline, SIGNAL(cursorChanged(double)), this, SLOT(onChangeCursor(double))); 49 | // connect(timeline, SIGNAL(startChanged(double)), ui->doubleSpinBox_startIn, SLOT(setValue(double))); 50 | connect(ui->widget_timeline, SIGNAL(startChanged(double)), this, SLOT(onChangeStart(double))); 51 | // connect(timeline, SIGNAL(endChanged(double)), ui->doubleSpinBox_endIn, SLOT(setValue(double))); 52 | connect(ui->widget_timeline, SIGNAL(endChanged(double)), this, SLOT(onChangeEnd(double))); 53 | 54 | connect(ui->widget_timeline, SIGNAL(keyPoseAdded(double)), this, SLOT(onAddKeyPose(double))); 55 | connect(ui->widget_timeline, SIGNAL(keyPoseDeleted(size_t)), this, SLOT(onDeleteKeyPose(size_t))); 56 | connect(ui->widget_timeline, SIGNAL(keyPoseChanged(size_t)), this, SLOT(onChangeKeyPose(size_t))); 57 | connect(ui->widget_timeline, SIGNAL(keyPosesMoved(double, size_t)), this, SLOT(onMoveKeyPoses(double, size_t))); 58 | connect(ui->widget_timeline, SIGNAL(keyPoseMoved(size_t, double)), this, SLOT(onMoveKeyPose(size_t, double))); 59 | 60 | connect(ui->widget_timeline, SIGNAL(envSaved()), this, SLOT(onSaveEnv())); 61 | connect(ui->widget_timeline, SIGNAL(rendered(void *)), this, SLOT(onRendering(void *))); 62 | // connect(timeline, &AnimTimeline::rendered, this, &MainWindow::onRendering); 63 | connect(ui->widget_timeline, &FormAnimTimelineWithSession::renderDeleted, this, &MainWindow::onDeleteRender); 64 | // connect(timeline, ) 65 | 66 | // connect(timeline, SIGNAL(envSaved()), this, SLOT(onSaveEnv())); 67 | // connect(timeline, SIGNAL(sessionCleared()), this, SLOT(onClearSession())); 68 | // connect(timeline, SIGNAL(undid()), this, SLOT(onUndo())); 69 | // connect(timeline, SIGNAL(redid()), this, SLOT(onRedo())); 70 | 71 | 72 | // --------------------------- ANIM_TIMELINE SLOTS ------------------------ 73 | // connect(ui->play, SIGNAL(clicked()), timeline, SLOT(onSetPlayMode())); 74 | // connect(ui->pause, SIGNAL(clicked()), timeline, SLOT(onSetPauseMode())); 75 | // connect(ui->durationOut, SIGNAL(valueChanged(double)), timeline, SLOT(onChangeAnimDuration(double))); 76 | 77 | // connect(ui->cursorOut, SIGNAL(valueChanged(double)), timeline, SLOT(onChangeCursor(double))); 78 | 79 | // connect(ui->addKeyPose, SIGNAL(clicked()), this, SLOT(onAddCursorKeyPose())); 80 | 81 | // std::vector vect{1, 5}; 82 | // timeline->onAddingKeyPose(6); 83 | 84 | ui->widget_timeline->show(); 85 | 86 | } 87 | 88 | MainWindow::~MainWindow() 89 | { 90 | delete ui; 91 | } 92 | 93 | 94 | // -------------------------- ANIM_TIMELINE SIGNALS --------------------------- 95 | void MainWindow::onPlay() 96 | { 97 | // qDebug() << "\033[35mplayClicked()\033[0m"; 98 | 99 | } 100 | 101 | void MainWindow::onPause() 102 | { 103 | // qDebug() << "\033[35mpauseClicked()\033[0m"; 104 | 105 | } 106 | 107 | void MainWindow::onChangeDuration(double time) 108 | { 109 | // qDebug() << "\033[35mdurationChanged(" << time << ")\033[0m"; 110 | ui->durationIn->setValue(time); 111 | 112 | } 113 | 114 | 115 | void MainWindow::onChangeCursor(double time) 116 | { 117 | // qDebug() << "\033[35mcursorChanged(" << time << ")\033[0m"; 118 | ui->cursorIn->setValue(time); 119 | 120 | } 121 | 122 | void MainWindow::onChangeStart(double time) 123 | { 124 | // qDebug() << "\033[35mstartChanged(" << time << ")\033[0m"; 125 | ui->doubleSpinBox_startIn->setValue(time); 126 | 127 | } 128 | 129 | void MainWindow::onChangeEnd(double time) 130 | { 131 | // qDebug() << "\033[35mendChanged(" << time << ")\033[0m"; 132 | ui->doubleSpinBox_endIn->setValue(time); 133 | 134 | } 135 | 136 | 137 | void MainWindow::onAddKeyPose(double time) 138 | { 139 | // qDebug() << "\033[35mkeyPoseAdded(" << time << ")\033[0m"; 140 | // ui->nbKeyPose->setValue(timeline->getNbKeyPoses()); 141 | ui->nbKeyPose->setValue(ui->nbKeyPose->value() +1); 142 | } 143 | 144 | void MainWindow::onDeleteKeyPose(size_t num) 145 | { 146 | // qDebug() << "\033[35mkeyPoseDeleted(" << num << ")\033[0m"; 147 | // ui->nbKeyPose->setValue(timeline->getNbKeyPoses()); 148 | ui->nbKeyPose->setValue(ui->nbKeyPose->value() -1); 149 | } 150 | 151 | void MainWindow::onChangeKeyPose(size_t num) 152 | { 153 | // qDebug() << "\033[35mkeyPoseChanged(" << num << ")\033[0m"; 154 | } 155 | 156 | 157 | void MainWindow::onMoveKeyPoses(double gap, size_t first) 158 | { 159 | // qDebug() << "\033[35mkeyPosesMoved(" << gap << ", " << first << ")\033[0m"; 160 | } 161 | 162 | void MainWindow::onMoveKeyPose(size_t num, double time) 163 | { 164 | // qDebug() << "\033[35mkeyPoseMoved(" << num << ", " << time << ")\033[0m"; 165 | 166 | } 167 | 168 | void MainWindow::onSaveEnv() 169 | { 170 | // qDebug() << "\033[35menvSaved()\033[0m"; 171 | 172 | // std::vector keyPoses{0.0}; 173 | // keyPoses.push_back(0.0); 174 | // keyPoses.push_back(1.0); 175 | // Env env; 176 | // struct s_Env env; 177 | // Anim a {0, 1.0, &keyPoses}; 178 | 179 | Anim * anim = static_cast(malloc(sizeof(struct s_Anim))); 180 | // *anim = a; 181 | anim->slider = ui->anim->value(); 182 | // anim->a = 0; 183 | // anim->b = 1.0; 184 | // anim->keyPoses = keyPoses; 185 | // anim{0, 1.0, keyPoses}; 186 | // Render * render = new Render(0, 0.0, keyPoses); 187 | // Render * render = (Render *)malloc(sizeof (struct s_render)); 188 | // render->a = 0; 189 | // render->b = 1.0; 190 | // render->keyPoses = {0, 1.0, 2}; 191 | 192 | ui->widget_timeline->onSaveRendering(anim, sizeof(*anim)); 193 | } 194 | 195 | void MainWindow::onRendering(void *render) 196 | { 197 | Anim * anim = static_cast(render); 198 | // qDebug() << "\033[35mrendered(" << anim << ")\033[0m"; 199 | 200 | ui->anim->setValue(anim->slider); 201 | } 202 | 203 | void MainWindow::onDeleteRender(void *render) 204 | { 205 | Anim * anim = static_cast(render); 206 | // qDebug() << "\033[35mrenderDeleted(" << anim << ")\033[0m"; 207 | 208 | free(anim); 209 | // delete(anim); 210 | } 211 | 212 | //void MainWindow::onRendering() 213 | //{ 214 | 215 | //} 216 | 217 | //void MainWindow::onClearSession() 218 | //{ 219 | // qDebug() << "\033[35menvsCleared()\033[0m"; 220 | 221 | //} 222 | 223 | //void MainWindow::onUndo() 224 | //{ 225 | // qDebug() << "\033[35mundid()\033[0m"; 226 | 227 | //} 228 | 229 | //void MainWindow::onRedo() 230 | //{ 231 | // qDebug() << "\033[35mredid()\033[0m"; 232 | 233 | //} 234 | 235 | 236 | 237 | // ------------------------------- OTHERS SLOTS ------------------------------- 238 | 239 | //void MainWindow::onAddCursorKeyPose() 240 | //{ 241 | // qDebug() << "\033[35madding keyPose current cursor \033[0m"; 242 | // timeline->onAddingKeyPose(ui->keyPose->value()); 243 | //} 244 | 245 | 246 | //void MainWindow::on_pushButton_clicked() 247 | //{ 248 | // ui->widget->onAddingKeyPose(ui->doubleSpinBox_4->value()); 249 | //} 250 | 251 | //void MainWindow::on_pushButton_2_clicked() 252 | //{ 253 | //// Dialog dialog; 254 | //// dialog.setModal(true); 255 | //// dialog.exec(); 256 | //// ui->widget->hide(); 257 | //// dialog = new Dialog(ui->widget, this); 258 | //// dialog->show(); 259 | 260 | //} 261 | 262 | void MainWindow::on_play_clicked() 263 | { 264 | ui->widget_timeline->onSetPlayMode(); 265 | } 266 | 267 | void MainWindow::on_pause_clicked() 268 | { 269 | ui->widget_timeline->onSetPauseMode(); 270 | } 271 | 272 | void MainWindow::on_durationOut_editingFinished() 273 | { 274 | // ui->widget_timeline->onChangeAnimDuration(ui->durationOut->value()); 275 | ui->widget_timeline->onChangeDuration(ui->durationOut->value()); 276 | } 277 | 278 | 279 | void MainWindow::on_cursorOut_editingFinished() 280 | { 281 | ui->widget_timeline->onChangeCursor(ui->cursorOut->value()); 282 | } 283 | 284 | void MainWindow::on_doubleSpinBox_startOut_editingFinished() 285 | { 286 | ui->widget_timeline->onChangeStart(ui->doubleSpinBox_startOut->value()); 287 | } 288 | 289 | void MainWindow::on_doubleSpinBox_endOut_editingFinished() 290 | { 291 | ui->widget_timeline->onChangeEnd(ui->doubleSpinBox_endOut->value()); 292 | } 293 | 294 | 295 | void MainWindow::on_keyPoseOut_editingFinished() 296 | { 297 | ui->widget_timeline->onAddingKeyPose(ui->keyPoseOut->value()); 298 | } 299 | 300 | void MainWindow::on_pushButton_clearKeyPoses_clicked() 301 | { 302 | ui->widget_timeline->onClearKeyPoses(); 303 | ui->nbKeyPose->setValue(0); 304 | } 305 | 306 | 307 | 308 | void MainWindow::on_pushButton_showTimeline_clicked() 309 | { 310 | ui->widget_timeline->show(); 311 | } 312 | 313 | void MainWindow::on_pushButton_hideTimeline_clicked() 314 | { 315 | ui->widget_timeline->hide(); 316 | } 317 | 318 | //void MainWindow::on_changeCursor_clicked() 319 | //{ 320 | // timeline->onChangeCursor(ui->cursorOut->value()); 321 | //} 322 | 323 | //void MainWindow::on_changeDuration_clicked() 324 | //{ 325 | // timeline->onChangeAnimDuration(ui->durationOut->value()); 326 | 327 | //} 328 | 329 | //void MainWindow::on_start_clicked() 330 | //{ 331 | // timeline->onChangeStart(ui->doubleSpinBox_startOut->value()); 332 | //} 333 | 334 | //void MainWindow::on_end_clicked() 335 | //{ 336 | // timeline->onChangeEnd(ui->doubleSpinBox_endOut->value()); 337 | 338 | //} 339 | 340 | 341 | 342 | -------------------------------------------------------------------------------- /mainwindow.h: -------------------------------------------------------------------------------- 1 | #ifndef MAINWINDOW_H 2 | #define MAINWINDOW_H 3 | 4 | #include 5 | //#include "dialog.h" 6 | #include 7 | //#include 8 | 9 | typedef struct s_Anim { 10 | int slider; 11 | double b; 12 | 13 | // std::vector * keyPoses; 14 | } Anim; 15 | 16 | namespace Ui { 17 | class MainWindow; 18 | } 19 | 20 | class MainWindow : public QMainWindow { 21 | Q_OBJECT 22 | 23 | public: 24 | explicit MainWindow(QWidget* parent = nullptr); 25 | ~MainWindow(); 26 | 27 | public slots: 28 | // animTimeline signals 29 | void onPlay(); 30 | void onPause(); 31 | void onChangeDuration(double time); 32 | 33 | void onChangeCursor(double time); 34 | void onChangeStart(double time); 35 | void onChangeEnd(double time); 36 | 37 | void onAddKeyPose(double time); 38 | void onDeleteKeyPose(size_t num); 39 | void onChangeKeyPose(size_t num); 40 | void onMoveKeyPoses(double gap, size_t first); 41 | void onMoveKeyPose(size_t num, double time); 42 | 43 | void onSaveEnv(); 44 | void onRendering(void * render); 45 | void onDeleteRender(void * render); 46 | // void onClearSession(); 47 | // void onUndo(); 48 | // void onRedo(); 49 | 50 | // void onAddCursorKeyPose(); 51 | 52 | private slots: 53 | 54 | // void on_pushButton_clicked(); 55 | 56 | // void on_pushButton_2_clicked(); 57 | 58 | // void on_changeCursor_clicked(); 59 | // void on_changeDuration_clicked(); 60 | // void on_start_clicked(); 61 | // void on_end_clicked(); 62 | void on_play_clicked(); 63 | void on_pause_clicked(); 64 | void on_durationOut_editingFinished(); 65 | 66 | void on_cursorOut_editingFinished(); 67 | void on_doubleSpinBox_startOut_editingFinished(); 68 | void on_doubleSpinBox_endOut_editingFinished(); 69 | 70 | void on_keyPoseOut_editingFinished(); 71 | void on_pushButton_clearKeyPoses_clicked(); 72 | 73 | 74 | 75 | void on_pushButton_showTimeline_clicked(); 76 | void on_pushButton_hideTimeline_clicked(); 77 | 78 | private: 79 | Ui::MainWindow* ui; 80 | // Dialog * dialog; 81 | // AnimTimeline* timeline; 82 | // AnimTimelineWithSession * timeline; 83 | // AnimSession * session; 84 | }; 85 | 86 | #endif // MAINWINDOW_H 87 | -------------------------------------------------------------------------------- /mainwindow.ui: -------------------------------------------------------------------------------- 1 | 2 | 3 | MainWindow 4 | 5 | 6 | 7 | 0 8 | 0 9 | 929 10 | 631 11 | 12 | 13 | 14 | MainWindow 15 | 16 | 17 | background: orange 18 | 19 | 20 | 21 | 22 | 23 | 24 | Qt::Vertical 25 | 26 | 27 | 28 | 29 | 0 30 | 0 31 | 32 | 33 | 34 | Qt::Horizontal 35 | 36 | 37 | 38 | 39 | 0 40 | 0 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 0 50 | 0 51 | 52 | 53 | 54 | Input/Output 55 | 56 | 57 | 58 | 59 | 450 60 | 80 61 | 101 62 | 21 63 | 64 | 65 | 66 | clearKeyPoses 67 | 68 | 69 | 70 | 71 | 72 | 30 73 | 160 74 | 62 75 | 22 76 | 77 | 78 | 79 | 4 80 | 81 | 82 | 9999.000000000000000 83 | 84 | 85 | 86 | 87 | 88 | 310 89 | 160 90 | 71 91 | 21 92 | 93 | 94 | 95 | 96 | 97 | 98 | 4 99 | 100 | 101 | -100.000000000000000 102 | 103 | 104 | 9999.000000000000000 105 | 106 | 107 | 108 | 109 | 110 | 160 111 | 140 112 | 80 113 | 21 114 | 115 | 116 | 117 | end 118 | 119 | 120 | 121 | 122 | 123 | 160 124 | 120 125 | 62 126 | 22 127 | 128 | 129 | 130 | true 131 | 132 | 133 | 134 | 135 | 136 | 750 137 | 160 138 | 61 139 | 21 140 | 141 | 142 | 143 | 144 | 145 | 146 | 4 147 | 148 | 149 | 9999.000000000000000 150 | 151 | 152 | 153 | 154 | 155 | 750 156 | 119 157 | 61 158 | 21 159 | 160 | 161 | 162 | true 163 | 164 | 165 | 166 | 167 | 168 | 169 | 170 | 171 | 30 172 | 140 173 | 80 174 | 21 175 | 176 | 177 | 178 | start 179 | 180 | 181 | 182 | 183 | 184 | 30 185 | 60 186 | 91 187 | 21 188 | 189 | 190 | 191 | show timeline 192 | 193 | 194 | 195 | 196 | 197 | 30 198 | 120 199 | 62 200 | 22 201 | 202 | 203 | 204 | true 205 | 206 | 207 | 208 | 209 | 210 | 580 211 | 160 212 | 80 213 | 21 214 | 215 | 216 | 217 | Pause 218 | 219 | 220 | 221 | 222 | 223 | 450 224 | 140 225 | 91 226 | 21 227 | 228 | 229 | 230 | add keyPose 231 | 232 | 233 | 234 | 235 | 236 | 450 237 | 160 238 | 61 239 | 21 240 | 241 | 242 | 243 | 244 | 245 | 246 | 4 247 | 248 | 249 | 9999.000000000000000 250 | 251 | 252 | 253 | 254 | 255 | 750 256 | 140 257 | 101 258 | 21 259 | 260 | 261 | 262 | duration 263 | 264 | 265 | 266 | 267 | 268 | 160 269 | 160 270 | 62 271 | 22 272 | 273 | 274 | 275 | 4 276 | 277 | 278 | 9999.000000000000000 279 | 280 | 281 | 282 | 283 | 284 | 580 285 | 130 286 | 80 287 | 21 288 | 289 | 290 | 291 | Play 292 | 293 | 294 | 295 | 296 | 297 | 310 298 | 140 299 | 91 300 | 21 301 | 302 | 303 | 304 | cursor 305 | 306 | 307 | 308 | 309 | 310 | 450 311 | 120 312 | 43 313 | 22 314 | 315 | 316 | 317 | true 318 | 319 | 320 | 321 | 322 | 323 | 310 324 | 120 325 | 71 326 | 21 327 | 328 | 329 | 330 | true 331 | 332 | 333 | 334 | 335 | 336 | 337 | 338 | 339 | 340 | 341 | 342 | 140 343 | 60 344 | 91 345 | 21 346 | 347 | 348 | 349 | hide timeline 350 | 351 | 352 | 353 | 354 | 355 | 390 356 | 240 357 | 160 358 | 16 359 | 360 | 361 | 362 | Qt::Horizontal 363 | 364 | 365 | 366 | 367 | 368 | 330 369 | 240 370 | 52 371 | 14 372 | 373 | 374 | 375 | anim 376 | 377 | 378 | 379 | 380 | 381 | 382 | 383 | 384 | 385 | 386 | 0 387 | 0 388 | 929 389 | 19 390 | 391 | 392 | 393 | 394 | 395 | TopToolBarArea 396 | 397 | 398 | false 399 | 400 | 401 | 402 | 403 | 404 | 405 | 406 | FormAnimTimelineWithSession 407 | QWidget 408 |
AnimTimeline/FormAnimTimeline.h
409 | 1 410 |
411 |
412 | 413 | 414 | 415 | cursorChanged(double) 416 | onChangeCursor(double) 417 | onPlay() 418 | onPause() 419 | onAddKeyPose(double) 420 | onKeyPoseChanged(int) 421 | onRemoveKeyPose(int) 422 | 423 |
424 | -------------------------------------------------------------------------------- /src/AnimTimeline/AnimTimelineSession.cpp: -------------------------------------------------------------------------------- 1 | #include "configurations.h" 2 | //#include 3 | #include "configurations.h" 4 | //#include 5 | #include "AnimTimelineSession.h" 6 | 7 | #include 8 | #include 9 | #include 10 | //#include // need boost lib 11 | 12 | AnimTimelineSession::AnimTimelineSession(QObject* parent) 13 | : QObject(parent) 14 | { 15 | saveDelay = new QTimer(this); 16 | connect(saveDelay, &QTimer::timeout, this, &AnimTimelineSession::envSaved); 17 | #ifndef QT_NO_DEBUG_OUTPUT 18 | connect(this, &AnimTimelineSession::envSaved, this, &AnimTimelineSession::envSavedTrace); 19 | #endif 20 | saveDelay->setSingleShot(true); 21 | } 22 | 23 | AnimTimelineSession::~AnimTimelineSession() 24 | { 25 | onClearSession(); 26 | delete saveDelay; 27 | } 28 | 29 | // timeline changed, save timeline and anim environment 30 | void AnimTimelineSession::onChangeEnv() 31 | { 32 | qDebug() << "AnimTimelineSession::onChangeEnv()"; 33 | saveDelay->start(AnimTimeline::DELAY_AUTO_SAVE); 34 | } 35 | 36 | void AnimTimelineSession::onClearSession() 37 | { 38 | while (!undo.empty()) { 39 | emit renderDeleted(undo.back().anim); 40 | qDebug() << "\033[35mrenderDeleted(" << undo.back().anim << ")\033[0m"; 41 | undo.pop_back(); 42 | } 43 | while (!redoHeap.empty()) { 44 | emit renderDeleted(redoHeap.top().anim); 45 | qDebug() << "\033[35mrenderDeleted(" << redoHeap.top().anim << ")\033[0m"; 46 | redoHeap.pop(); 47 | } 48 | 49 | size = 0; 50 | 51 | onChangeEnv(); 52 | } 53 | 54 | void AnimTimelineSession::onUndo() 55 | { 56 | if (undo.empty()) { 57 | qDebug() << "\033[31mSession::onUndo() : empty buffer ! (suggestion for client : " 58 | "you need to catch envSaved to launch onSaveRendering with your anim " 59 | "structure due of undo/redo calling, wanted to restore your environment\033[0m"; 60 | return; 61 | } 62 | 63 | if (undo.size() > 1) { 64 | redoHeap.push(undo.back()); 65 | undo.pop_back(); 66 | 67 | setEnv(undo.back()); 68 | } else { 69 | qDebug() << "\033[31mSession::onUndo() : last element, can't delete !\033[0m"; 70 | } 71 | } 72 | 73 | void AnimTimelineSession::onRedo() 74 | { 75 | if (redoHeap.empty()) { 76 | qDebug() << "\033[31mSession::onRedo() : empty stack !\033[0m"; 77 | return; 78 | } 79 | 80 | undo.emplace_back(redoHeap.top()); 81 | redoHeap.pop(); 82 | 83 | setEnv(undo.back()); 84 | } 85 | 86 | void AnimTimelineSession::onSaveRendering(void* anim, size_t bytes) 87 | { 88 | 89 | while (!redoHeap.empty()) { 90 | emit renderDeleted(redoHeap.top().anim); 91 | qDebug() << "\033[35mrenderDeleted(" << redoHeap.top().anim << ")\033[0m"; 92 | size -= redoHeap.top().bytes; 93 | redoHeap.pop(); 94 | } 95 | 96 | undo.emplace_back(Env { *start, *end, *cursor, *duration, *keyPoses, anim, bytes }); 97 | size += bytes; 98 | 99 | while (size > AnimTimeline::BUFFER_SESSION_MAX_SIZE) { 100 | qDebug() << "\033[31monSaveRendering : buffer overflow\033[0m"; 101 | emit renderDeleted(undo.front().anim); 102 | qDebug() << "\033[35mrenderDeleted(" << undo.front().anim << ")\033[0m"; 103 | size -= undo.front().bytes; 104 | undo.pop_front(); 105 | } 106 | 107 | qDebug() << "AnimTimelineSession::onSaveRendering() : buff size (bytes) =" << size << "/" << AnimTimeline::BUFFER_SESSION_MAX_SIZE << "(" << size * 100.0 / AnimTimeline::BUFFER_SESSION_MAX_SIZE << "% )"; 108 | } 109 | 110 | void AnimTimelineSession::setEnv(Env env) 111 | { 112 | *start = env.start; 113 | selector->updateStartSpin(); 114 | 115 | *end = env.end; 116 | selector->updateEndSpin(); 117 | 118 | *keyPoses = env.keyPoses; 119 | nbKeyPosesSpin->setValue(static_cast(keyPoses->size())); 120 | 121 | selector->updateCursorSpin(); 122 | 123 | *duration = env.duration; 124 | selector->updateDurationSpin(); 125 | 126 | // selector->redrawPlayZone(); 127 | ruler->onDrawRuler(ruler->width()); 128 | 129 | emit rendered(env.anim); 130 | qDebug() << "\033[35mrendered(" << env.anim << ")\033[0m"; 131 | } 132 | 133 | #ifndef QT_NO_DEBUG_OUTPUT 134 | void AnimTimelineSession::envSavedTrace() 135 | { 136 | qDebug() << "\033[35menvSaved()\033[0m"; 137 | } 138 | #endif 139 | 140 | void AnimTimelineSession::setKeyPoses(std::set* value) 141 | { 142 | keyPoses = value; 143 | } 144 | 145 | void AnimTimelineSession::setDuration(double* value) 146 | { 147 | duration = value; 148 | } 149 | 150 | void AnimTimelineSession::setCursor(double* value) 151 | { 152 | cursor = value; 153 | } 154 | 155 | void AnimTimelineSession::setEnd(double* value) 156 | { 157 | end = value; 158 | } 159 | 160 | void AnimTimelineSession::setStart(double* value) 161 | { 162 | start = value; 163 | } 164 | 165 | void AnimTimelineSession::setDurationSpin(QDoubleSpinBoxSmart* value) 166 | { 167 | durationSpin = value; 168 | } 169 | 170 | void AnimTimelineSession::setCursorSpin(QDoubleSpinBoxSmart* value) 171 | { 172 | cursorSpin = value; 173 | } 174 | 175 | void AnimTimelineSession::setEndSpin(QDoubleSpinBoxSmart* value) 176 | { 177 | endSpin = value; 178 | } 179 | 180 | void AnimTimelineSession::setStartSpin(QDoubleSpinBoxSmart* value) 181 | { 182 | startSpin = value; 183 | } 184 | 185 | void AnimTimelineSession::setNbKeyPosesSpin(QSpinBoxSmart* value) 186 | { 187 | nbKeyPosesSpin = value; 188 | } 189 | 190 | void AnimTimelineSession::setSelector(QFrameSelector* value) 191 | { 192 | selector = value; 193 | } 194 | 195 | void AnimTimelineSession::setRuler(QWidgetRuler* value) 196 | { 197 | ruler = value; 198 | } 199 | 200 | void AnimTimelineSession::setPlayButton(QToolButtonPlayPause* value) 201 | { 202 | playButton = value; 203 | } 204 | -------------------------------------------------------------------------------- /src/AnimTimeline/AnimTimelineSession.h: -------------------------------------------------------------------------------- 1 | #ifndef ANIM_TIMELINE_SESSION_H 2 | #define ANIM_TIMELINE_SESSION_H 3 | 4 | //#include 5 | #include "qdoublespinboxsmart.h" 6 | //#include 7 | #include "qframeselector.h" 8 | //#include 9 | #include "qspinboxsmart.h" 10 | //#include 11 | #include "qtoolbuttonplaypause.h" 12 | //#include 13 | #include "qwidgetruler.h" 14 | 15 | #include 16 | #include 17 | 18 | class AnimTimelineSession : public QObject { 19 | Q_OBJECT 20 | public: 21 | AnimTimelineSession(QObject* parent = nullptr); 22 | virtual ~AnimTimelineSession(); 23 | 24 | signals: 25 | void envSaved(); // EXTERNAL 26 | 27 | void rendered(void* render); // EXTERNAL 28 | void renderDeleted(void* render); // EXTERNAL 29 | 30 | public slots: 31 | void onChangeEnv(); 32 | 33 | void onClearSession(); 34 | void onUndo(); 35 | void onRedo(); 36 | 37 | void onSaveRendering(void* anim, size_t bytes); // EXTERNAL 38 | 39 | private: 40 | typedef struct s_Env { 41 | double start; 42 | double end; 43 | double cursor; 44 | double duration; 45 | 46 | std::set keyPoses; 47 | 48 | void* anim; 49 | size_t bytes; 50 | } Env; 51 | 52 | std::deque undo; 53 | std::stack redoHeap; 54 | 55 | Env first; 56 | 57 | double* start; 58 | double* end; 59 | double* cursor; 60 | double* duration; 61 | std::set* keyPoses; 62 | 63 | size_t size { 0 }; 64 | 65 | QDoubleSpinBoxSmart* startSpin; 66 | QDoubleSpinBoxSmart* endSpin; 67 | QDoubleSpinBoxSmart* cursorSpin; 68 | QDoubleSpinBoxSmart* durationSpin; 69 | 70 | QToolButtonPlayPause* playButton; 71 | 72 | QWidgetRuler* ruler; 73 | 74 | QTimer* saveDelay; 75 | QFrameSelector* selector; 76 | QSpinBoxSmart* nbKeyPosesSpin; 77 | 78 | private: 79 | void setEnv(Env env); 80 | 81 | #ifndef QT_NO_DEBUG_OUTPUT 82 | void envSavedTrace(); 83 | #endif 84 | 85 | public: // setters 86 | void setStart(double* value); 87 | void setEnd(double* value); 88 | void setCursor(double* value); 89 | void setDuration(double* value); 90 | void setKeyPoses(std::set* value); 91 | void setStartSpin(QDoubleSpinBoxSmart* value); 92 | void setEndSpin(QDoubleSpinBoxSmart* value); 93 | void setCursorSpin(QDoubleSpinBoxSmart* value); 94 | void setDurationSpin(QDoubleSpinBoxSmart* value); 95 | void setPlayButton(QToolButtonPlayPause* value); 96 | void setRuler(QWidgetRuler* value); 97 | void setSelector(QFrameSelector* value); 98 | void setNbKeyPosesSpin(QSpinBoxSmart* value); 99 | }; 100 | 101 | #endif // ANIM_TIMELINE_SESSION_H 102 | -------------------------------------------------------------------------------- /src/AnimTimeline/FormAnimTimeline.cpp: -------------------------------------------------------------------------------- 1 | #include "FormAnimTimeline.h" 2 | #include "ui_FormAnimTimeline.h" // moc not found in , created on build 3 | //#include 4 | 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | 12 | FormAnimTimeline::FormAnimTimeline(QWidget* parent) 13 | : QWidget(parent) 14 | ,ui(new Ui::FormAnimTimeline) 15 | 16 | { 17 | ui->setupUi(this); 18 | // qDebug() << "AnimTimeline::AnimTimeline(" << parent << ") : ui setup end"; 19 | 20 | // --------------------------- INTERNAL CONNECTIONS ----------------------- 21 | // FRAME_BUTTONS 22 | connect(ui->toolButton_help, &QToolButton::clicked, ui->frame_buttons, &QFrameButtons::helpClicked); 23 | 24 | // FRAME_SELECTOR 25 | connect(ui->doubleSpinBox_start, &QDoubleSpinBoxSmart::editingFinished, ui->frame_selector, &QFrameSelector::onChangeStartSpin); 26 | connect(ui->doubleSpinBox_end, &QDoubleSpinBoxSmart::editingFinished, ui->frame_selector, &QFrameSelector::onChangeEndSpin); 27 | connect(ui->doubleSpinBox_cursor, &QDoubleSpinBoxSmart::editingFinished, ui->frame_selector, &QFrameSelector::onChangeCursorSpin); 28 | connect(ui->doubleSpinBox_maxDuration, &QDoubleSpinBoxSmart::editingFinished, ui->frame_selector, &QFrameSelector::onChangeDurationSpin); 29 | 30 | // connect(ui->widget_leftSlider, &QWidgetSlider::slide, ui->frame_selector, &QFrameSelector::onSlideLeftSlider); 31 | ui->splitter->setCollapsible(0, false); 32 | ui->splitter->setCollapsible(2, false); 33 | connect(ui->splitter, &QSplitter::splitterMoved, ui->frame_selector, &QFrameSelector::onSplitterMove); 34 | // connect(ui->widget_leftSlider, &QWidgetSlider::slideRelease, ui->frame_selector, &QFrameSelector::onLeftSlideRelease); 35 | // connect(ui->widget_rightSlider, &QWidgetSlider::slide, ui->frame_selector, &QFrameSelector::onSlideRightSlider); 36 | // connect(ui->widget_rightSlider, &QWidgetSlider::slideRelease, ui->frame_selector, &QFrameSelector::onRightSlideRelease); 37 | connect(ui->scrollAreaWidgetContents, &QWidgetRuler::rulerChanged, ui->frame_selector, &QFrameSelector::onRulerChange); 38 | connect(ui->scrollAreaWidgetContents, &QWidgetRuler::rulerChanged, ui->frame_timescale, &QFrameTimescale::onRulerChange); 39 | 40 | connect(ui->scrollArea, &QScrollAreaRuler::removeKeyPose, ui->frame_selector, &QFrameSelector::onDeleteKeyPose); 41 | connect(ui->scrollArea, SIGNAL(addKeyPose()), ui->frame_selector, SLOT(onAddingKeyPose())); 42 | connect(ui->scrollArea, &QScrollAreaRuler::nextKeyPose, ui->frame_selector, &QFrameSelector::onSetCursorToNextKeyPose); 43 | connect(ui->scrollArea, &QScrollAreaRuler::previousKeyPose, ui->frame_selector, &QFrameSelector::onSetCursorToPreviousKeyPose); 44 | connect(ui->scrollArea, SIGNAL(durationChanged(double)), ui->frame_selector, SLOT(onChangeDuration(double))); 45 | 46 | connect(ui->toolButton_deleteKeyPose, &QToolButton::clicked, ui->frame_selector, &QFrameSelector::onDeleteKeyPose); 47 | connect(ui->toolButton_end, &QToolButton::clicked, ui->frame_selector, &QFrameSelector::onSetCursorToEnd); 48 | connect(ui->toolButton_forward, &QToolButton::clicked, ui->frame_selector, &QFrameSelector::onSetCursorToNextKeyPose); 49 | connect(ui->toolButton_keyPose, SIGNAL(clicked()), ui->frame_selector, SLOT(onAddingKeyPose())); 50 | 51 | connect(ui->toolButton_rearward, &QToolButton::clicked, ui->frame_selector, &QFrameSelector::onSetCursorToPreviousKeyPose); 52 | connect(ui->toolButton_start, &QToolButton::clicked, ui->frame_selector, &QFrameSelector::onSetCursorToStart); 53 | 54 | connect(ui->spinBox_nbKeyPoses, &QSpinBoxSmart::nextKeyPose, ui->frame_selector, &QFrameSelector::onSetCursorToNextKeyPose); 55 | connect(ui->spinBox_nbKeyPoses, &QSpinBoxSmart::previousKeyPose, ui->frame_selector, &QFrameSelector::onSetCursorToPreviousKeyPose); 56 | connect(ui->spinBox_nbKeyPoses, &QSpinBoxSmart::deleteKeyPose, ui->frame_selector, &QFrameSelector::onDeleteKeyPose); 57 | 58 | // SCROLL_AREA_RULER 59 | connect(ui->frame_buttons, &QFrameButtons::keyPressed, ui->scrollArea, &QScrollAreaRuler::onKeyPress); 60 | connect(ui->frame_buttons, &QFrameButtons::keyReleased, ui->scrollArea, &QScrollAreaRuler::onKeyRelease); 61 | 62 | // --------------------------- SET INTERNAL REFERENCES -------------------- 63 | // FRAME_SELECTOR 64 | ui->frame_selector->setPlayZone(ui->frame_playZone); 65 | // ui->frame_selector->setLeftSlider(ui->widget_leftSlider); 66 | ui->frame_selector->setLeftSpacer(ui->frame_spacer); 67 | ui->frame_selector->setRightSpacer(ui->frame_rightSpacer); 68 | // ui->frame_selector->setRightSlider(ui->widget_rightSlider); 69 | ui->frame_selector->setCursorSpin(ui->doubleSpinBox_cursor); 70 | ui->frame_selector->setStartSpin(ui->doubleSpinBox_start); 71 | ui->frame_selector->setEndSpin(ui->doubleSpinBox_end); 72 | ui->frame_selector->setRemoveKeyPoseButton(ui->toolButton_deleteKeyPose); 73 | ui->frame_selector->setDurationSpin(ui->doubleSpinBox_maxDuration); 74 | ui->frame_selector->setNbKeyPosesSpin(ui->spinBox_nbKeyPoses); 75 | ui->frame_selector->setShiftDown(ui->scrollArea->getShiftDown()); 76 | ui->frame_selector->setMidMouseDown(ui->scrollArea->getMidMouseDown()); 77 | ui->frame_selector->setCtrlDown(ui->scrollArea->getCtrlDown()); 78 | ui->frame_selector->setSplitter(ui->splitter); 79 | 80 | // FRAME_BUTTONS 81 | ui->frame_buttons->setAnimTimeline(this); 82 | ui->frame_buttons->setRuler(ui->scrollAreaWidgetContents); 83 | ui->frame_buttons->setHelpButton(ui->toolButton_help); 84 | 85 | // SCROLL_AREA_RULER 86 | ui->scrollArea->setAnimTimeline(this); 87 | ui->scrollArea->setRuler(ui->scrollAreaWidgetContents); 88 | ui->scrollArea->setPlayPause(ui->toolButton_playPause); 89 | ui->scrollArea->setSpinDuration(ui->doubleSpinBox_maxDuration); 90 | ui->scrollArea->setSelector(ui->frame_selector); 91 | ui->scrollArea->setCursorSpin(ui->doubleSpinBox_cursor); 92 | 93 | // WIDGET_RULER 94 | ui->scrollAreaWidgetContents->setSpinStart(ui->doubleSpinBox_start); 95 | ui->scrollAreaWidgetContents->setSpinEnd(ui->doubleSpinBox_end); 96 | ui->scrollAreaWidgetContents->setSpinCursor(ui->doubleSpinBox_cursor); 97 | ui->scrollAreaWidgetContents->setSpinDuration(ui->doubleSpinBox_maxDuration); 98 | ui->scrollAreaWidgetContents->setShiftDown(ui->scrollArea->getShiftDown()); 99 | ui->scrollAreaWidgetContents->setCtrlDown(ui->scrollArea->getCtrlDown()); 100 | 101 | // --------------------------- SET DEFAULT UI VALUES ---------------------- 102 | // FRAME_SELECTOR 103 | ui->frame_selector->setStart(ui->doubleSpinBox_start->value()); 104 | ui->frame_selector->setCursor(ui->doubleSpinBox_cursor->value()); 105 | ui->frame_selector->setEnd(ui->doubleSpinBox_end->value()); 106 | ui->frame_selector->setDuration(ui->doubleSpinBox_maxDuration->value()); 107 | 108 | // ------------- CONNECT INTERNAL SIGNAL TO EXTERNAL SIGNAL --------------- 109 | connect(ui->toolButton_playPause, &QToolButtonPlayPause::playClicked, this, &FormAnimTimeline::playClicked); 110 | connect(ui->toolButton_playPause, &QToolButtonPlayPause::pauseClicked, this, &FormAnimTimeline::pauseClicked); 111 | 112 | connect(ui->frame_selector, &QFrameSelector::cursorChanged, this, &FormAnimTimeline::cursorChanged); 113 | connect(ui->frame_selector, &QFrameSelector::startChanged, this, &FormAnimTimeline::startChanged); 114 | connect(ui->frame_selector, &QFrameSelector::endChanged, this, &FormAnimTimeline::endChanged); 115 | connect(ui->frame_selector, &QFrameSelector::durationChanged, this, &FormAnimTimeline::durationChanged); 116 | connect(ui->frame_selector, &QFrameSelector::keyPoseAdded, this, &FormAnimTimeline::keyPoseAdded); 117 | connect(ui->frame_selector, &QFrameSelector::keyPoseDeleted, this, &FormAnimTimeline::keyPoseDeleted); 118 | connect(ui->frame_selector, &QFrameSelector::keyPoseChanged, this, &FormAnimTimeline::keyPoseChanged); 119 | connect(ui->frame_selector, &QFrameSelector::keyPosesMoved, this, &FormAnimTimeline::keyPosesMoved); 120 | connect(ui->frame_selector, &QFrameSelector::keyPoseMoved, this, &FormAnimTimeline::keyPoseMoved); 121 | 122 | // move timeline into parent (not nil) or screen area 123 | // QRect rec = QApplication::desktop()->screenGeometry(); 124 | // int rightBorder = (parent) ? (parent->x() + parent->width()) : (rec.x() + rec.width()); 125 | // int bottomBorder = (parent) ? (parent->y() + parent->height()) : (rec.y() + rec.height()); 126 | 127 | // int timelineLeft = rightBorder - this->width() - MARGIN_RIGHT; 128 | // int timelineTop = bottomBorder - this->height() - MARGIN_DOWN; 129 | // move(timelineLeft, timelineTop); 130 | 131 | // set sizePolicy to allow zoom in scrollArea 132 | ui->scrollAreaWidgetContents->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Preferred); 133 | // first draw of ruler with current width (default in animtimeline.ui) of dialog 134 | ui->scrollAreaWidgetContents->onDrawRuler(width() - 2); // left/right border width = 2 *1 pixel 135 | } 136 | 137 | FormAnimTimeline::~FormAnimTimeline() { delete ui; } 138 | 139 | // todo : ctrlDown = shiftDown = false, on focus event (initialize state) 140 | void FormAnimTimeline::resizeEvent(QResizeEvent* event) 141 | { 142 | qDebug() << "FormAnimTimeline::resizeEvent(" << event->size() << ")"; 143 | 144 | ui->scrollAreaWidgetContents->onDrawRuler(event->size().width() - 2); 145 | } 146 | 147 | // ------------------------------- EXTERNAL SLOTS ----------------------------- 148 | void FormAnimTimeline::onChangeStart(double time) 149 | { 150 | qDebug() << "\033[32monChangeStart(" << time << ")\033[0m"; 151 | ui->frame_selector->onChangeStart(time, false); 152 | } 153 | 154 | void FormAnimTimeline::onChangeEnd(double time) 155 | { 156 | qDebug() << "\033[32monChangeEnd(" << time << ")\033[0m"; 157 | ui->frame_selector->onChangeEnd(time, false); 158 | } 159 | 160 | void FormAnimTimeline::onChangeCursor(double time) 161 | { 162 | qDebug() << "\033[32monChangeCursor(" << time << ")\033[0m"; 163 | ui->frame_selector->onChangeCursor(time, false); 164 | } 165 | 166 | void FormAnimTimeline::onChangeDuration(double time) 167 | { 168 | qDebug() << "\033[32monChangeDuration(" << time << ")\033[0m"; 169 | ui->frame_selector->onChangeDuration(time, false); 170 | } 171 | 172 | void FormAnimTimeline::onAddingKeyPose(double time) 173 | { 174 | qDebug() << "\033[32monAddingKeyPose(" << time << ")\033[0m"; 175 | ui->frame_selector->onAddingKeyPose(time, false); 176 | } 177 | 178 | void FormAnimTimeline::onClearKeyPoses() 179 | { 180 | qDebug() << "\033[32monClearKeyPoses()\033[0m"; 181 | ui->frame_selector->onClearKeyPoses(); 182 | } 183 | 184 | void FormAnimTimeline::onSetPlayMode() 185 | { 186 | qDebug() << "\033[32monSetPlayMode()\033[0m"; 187 | ui->toolButton_playPause->onPlayMode(); 188 | } 189 | 190 | void FormAnimTimeline::onSetPauseMode() 191 | { 192 | qDebug() << "\033[32monSetPauseMode()\033[0m"; 193 | ui->toolButton_playPause->onPauseMode(); 194 | } 195 | 196 | FormAnimTimelineWithSession::FormAnimTimelineWithSession(QWidget* parent) 197 | : FormAnimTimeline(parent) 198 | { 199 | connect(this, &FormAnimTimelineWithSession::startChanged, &session, &AnimTimelineSession::onChangeEnv); 200 | connect(this, &FormAnimTimelineWithSession::endChanged, &session, &AnimTimelineSession::onChangeEnv); 201 | // connect(this, &FormAnimTimelineWithSession::cursorChanged, this, &AnimTimelineSession::onChangeEnv); 202 | connect(this, &FormAnimTimelineWithSession::durationChanged, &session, &AnimTimelineSession::onChangeEnv); 203 | connect(this, &FormAnimTimelineWithSession::keyPoseAdded, &session, &AnimTimelineSession::onChangeEnv); 204 | connect(this, &FormAnimTimelineWithSession::keyPoseDeleted, &session, &AnimTimelineSession::onChangeEnv); 205 | connect(this, &FormAnimTimelineWithSession::keyPoseChanged, &session, &AnimTimelineSession::onChangeEnv); 206 | connect(this, &FormAnimTimelineWithSession::keyPoseMoved, &session, &AnimTimelineSession::onChangeEnv); 207 | connect(this, &FormAnimTimelineWithSession::keyPosesMoved, &session, &AnimTimelineSession::onChangeEnv); 208 | // connect(this, &FormAnimTimelineWithSession::playClicked, &session, &AnimTimelineSession::onChangeEnv); 209 | // connect(this, &FormAnimTimelineWithSession::pauseClicked, &session, &AnimTimelineSession::onChangeEnv); 210 | 211 | connect(ui->scrollArea, &QScrollAreaRuler::undo, &session, &AnimTimelineSession::onUndo); 212 | connect(ui->scrollArea, &QScrollAreaRuler::redo, &session, &AnimTimelineSession::onRedo); 213 | 214 | // signal to signal 215 | connect(&session, &AnimTimelineSession::envSaved, this, &FormAnimTimelineWithSession::envSaved); 216 | connect(&session, &AnimTimelineSession::rendered, this, &FormAnimTimelineWithSession::rendered); 217 | connect(&session, &AnimTimelineSession::renderDeleted, this, &FormAnimTimelineWithSession::renderDeleted); 218 | 219 | session.setStart(ui->frame_selector->getStart()); 220 | session.setEnd(ui->frame_selector->getEnd()); 221 | session.setCursor(ui->frame_selector->getCursor()); 222 | session.setDuration(ui->scrollAreaWidgetContents->getMaxDuration()); 223 | session.setKeyPoses(ui->frame_selector->getKeyPoses()); 224 | session.setStartSpin(ui->doubleSpinBox_start); 225 | session.setEndSpin(ui->doubleSpinBox_end); 226 | session.setCursorSpin(ui->doubleSpinBox_cursor); 227 | session.setDurationSpin(ui->doubleSpinBox_maxDuration); 228 | session.setPlayButton(ui->toolButton_playPause); 229 | session.setRuler(ui->scrollAreaWidgetContents); 230 | session.setSelector(ui->frame_selector); 231 | session.setNbKeyPosesSpin(ui->spinBox_nbKeyPoses); 232 | } 233 | 234 | void FormAnimTimelineWithSession::onChangeStart(double time) 235 | { 236 | FormAnimTimeline::onChangeStart(time); 237 | 238 | session.onClearSession(); 239 | } 240 | 241 | void FormAnimTimelineWithSession::onChangeEnd(double time) 242 | { 243 | FormAnimTimeline::onChangeEnd(time); 244 | 245 | session.onClearSession(); 246 | } 247 | 248 | void FormAnimTimelineWithSession::onChangeDuration(double time) 249 | { 250 | FormAnimTimeline::onChangeDuration(time); 251 | 252 | session.onClearSession(); 253 | } 254 | 255 | void FormAnimTimelineWithSession::onAddingKeyPose(double time) 256 | { 257 | FormAnimTimeline::onAddingKeyPose(time); 258 | 259 | session.onClearSession(); 260 | } 261 | 262 | void FormAnimTimelineWithSession::onClearKeyPoses() 263 | { 264 | FormAnimTimeline::onClearKeyPoses(); 265 | 266 | session.onClearSession(); 267 | } 268 | 269 | void FormAnimTimelineWithSession::onSaveRendering(void* anim, size_t bytes) 270 | { 271 | qDebug() << "\033[32monSaveRendering(" << anim << ", " << bytes << ")\033[0m"; 272 | session.onSaveRendering(anim, bytes); 273 | } 274 | -------------------------------------------------------------------------------- /src/AnimTimeline/FormAnimTimeline.h: -------------------------------------------------------------------------------- 1 | /*! 2 | * \brief Custom Qt widget for animation (timeline) 3 | * \author Gauthier Bouyjou (email : gauthierbouyjou@aol.com) 4 | * \date april 2019 5 | * 6 | * For question send me mail or add issue to initial 7 | * github repo : https://github.com/hiergaut/AnimTimeline.git 8 | * current commit id : 93854c5c91578430aa6efb665b7b63773ade4619 9 | */ 10 | 11 | #ifndef ANIMTIMELINE_H 12 | #define ANIMTIMELINE_H 13 | 14 | //#include 15 | #include "AnimTimelineSession.h" 16 | 17 | #include 18 | #include 19 | 20 | namespace Ui { 21 | class FormAnimTimeline; 22 | } 23 | 24 | /*! 25 | * \brief The FormAnimTimeline class is a minimal specification of timeline abilities 26 | */ 27 | class FormAnimTimeline : public QWidget { 28 | Q_OBJECT 29 | 30 | public: 31 | explicit FormAnimTimeline(QWidget* parent = nullptr); 32 | ~FormAnimTimeline() override; 33 | 34 | protected: 35 | virtual void resizeEvent(QResizeEvent* ev) override; 36 | 37 | //signals: 38 | // void startChanged(double time); 39 | // void endChanged(double time); 40 | // void cursorChanged(double time); 41 | // void durationChanged(double time); 42 | 43 | // void keyPoseAdded(double time); 44 | // void keyPoseDeleted(size_t id); 45 | // void keyPoseChanged(size_t id); 46 | // void keyPoseMoved(size_t id, double time); 47 | // void keyPosesMoved(double gap, size_t first = 0); 48 | 49 | // void playClicked(); 50 | // void pauseClicked(); 51 | 52 | //public slots: 53 | // virtual void onChangeStart(double time); 54 | // virtual void onChangeEnd(double time); 55 | // virtual void onChangeCursor(double time); 56 | // virtual void onChangeDuration(double time); 57 | 58 | // virtual void onAddingKeyPose(double time); 59 | // virtual void onClearKeyPoses(); 60 | // virtual void onSetPlayMode(); // use it if external play button 61 | // virtual void onSetPauseMode(); // use it if external pause button 62 | 63 | //protected: 64 | // Ui::FormAnimTimeline* ui; 65 | 66 | signals: 67 | /*! 68 | * \brief startChanged is emitted when user move left slider of playzone or set new value in start spin (green) 69 | * \param time is the new start time for playzone 70 | */ 71 | void startChanged(double time); 72 | /*! 73 | * \brief endChanged is emitted when user move right slider of playzone or set new value in end spin (red) 74 | * \param time is the new end time for playzone 75 | */ 76 | void endChanged(double time); 77 | /*! 78 | * \brief cursorChanged is emitted when user move cursor 79 | * \param time is the new time of cursor to render in engine 80 | */ 81 | void cursorChanged(double time); 82 | /*! 83 | * \brief durationChanged is emitted when user change duration time in top right spin 84 | * \param time is the new time for animation 85 | */ 86 | void durationChanged(double time); 87 | 88 | /*! 89 | * \brief keyPoseAdded is emitted when user add new keyPose 90 | * \param time is the time of new keyPose, if a keyPose is already here so signal keyPoseChanged is called 91 | */ 92 | void keyPoseAdded(double time); 93 | /*! 94 | * \brief keyPoseDeleted is emitted when user remove keyPose 95 | * \param id is the ith keyPose to remove (chronological order) 96 | */ 97 | void keyPoseDeleted(size_t id); 98 | /*! 99 | * \brief keyPoseChanged is emitted when user insert keyPose in a known keyPose position 100 | * \param id is the ith keyPose to change 101 | */ 102 | void keyPoseChanged(size_t id); 103 | /*! 104 | * \brief keyPoseMoved is emitted when user move keyPose on cursor to new position (on mouse) 105 | * \param id is the ith keyPose to move 106 | * \param time is the time of keyPose, move current keyPose in other keyPose is not possible 107 | */ 108 | void keyPoseMoved(size_t id, double time); 109 | /*! 110 | * \brief keyPosesMoved is emitted when user move keyPoses 111 | * \param gap is the sliding distance for moving 112 | * \param first is the first keyPose to move with its right brothers 113 | */ 114 | void keyPosesMoved(double gap, size_t first = 0); 115 | 116 | /*! 117 | * \brief playClicked is emitted when user click on play button 118 | */ 119 | void playClicked(); 120 | /*! 121 | * \brief pauseClicked is emitted when user click on pause button 122 | */ 123 | void pauseClicked(); 124 | 125 | public slots: 126 | /*! 127 | * \brief onChangeStart change start in timeline 128 | * \param time is the new start 129 | */ 130 | virtual void onChangeStart(double time); 131 | /*! 132 | * \brief onChangeEnd change end in timeline 133 | * \param time is the new end 134 | */ 135 | virtual void onChangeEnd(double time); 136 | /*! 137 | * \brief onChangeCursor change cursor in timeline 138 | * \param time is the new cursor 139 | */ 140 | virtual void onChangeCursor(double time); 141 | /*! 142 | * \brief onChangeDuration change duration in timeline 143 | * \param time is the new duration 144 | */ 145 | virtual void onChangeDuration(double time); 146 | 147 | /*! 148 | * \brief onAddingKeyPose add keyPose in timeline 149 | * \param time is the new keyPose time 150 | */ 151 | virtual void onAddingKeyPose(double time); 152 | /*! 153 | * \brief onClearKeyPoses remove all keyPoses in timeline 154 | */ 155 | virtual void onClearKeyPoses(); 156 | 157 | /*! 158 | * \brief onSetPlayMode set play mode in timeline 159 | */ 160 | virtual void onSetPlayMode(); // use it if external play button 161 | /*! 162 | * \brief onSetPauseMode set pause mode in timeline 163 | */ 164 | virtual void onSetPauseMode(); // use it if external pause button 165 | 166 | protected: 167 | Ui::FormAnimTimeline* ui; 168 | }; 169 | 170 | /*! 171 | * \brief The FormAnimTimelineWithSession class is a FormAnimTimeline with session, permit (undo/redo) 172 | */ 173 | class FormAnimTimelineWithSession : public FormAnimTimeline { 174 | Q_OBJECT 175 | 176 | public: 177 | explicit FormAnimTimelineWithSession(QWidget* parent = nullptr); 178 | 179 | signals: 180 | /*! 181 | * \brief envSaved is emitted for session, after receive this signal, user must call 182 | * onSaveRendering slot of FormAnimTimeline to save client anim to render later due of undo/redo envent 183 | */ 184 | void envSaved(); 185 | /*! 186 | * \brief rendered is emmited when undo/redo envent is calling and need to render previous environment 187 | * \param is the environment to render, anim is void* because Qt Q_OBJECT no accept template class 188 | * and signal and slots are needed to send signal to user to render 189 | */ 190 | void rendered(void* anim); 191 | /*! 192 | * \brief renderDeleted is emmited when environment is not needed for future 193 | * \param anim is the environment to delete 194 | */ 195 | void renderDeleted(void* anim); 196 | 197 | public slots: 198 | /*! 199 | * \brief onSaveRendering must be called by user after envSaved receive 200 | * \param anim is the minimal environment to save in timeline session to render later 201 | * \param bytes is the size of minimal environment, permit to save RAM 202 | */ 203 | void onSaveRendering(void* anim, size_t bytes); 204 | 205 | public slots: 206 | void onChangeStart(double time) override; 207 | void onChangeEnd(double time) override; 208 | // void onChangeCursor(double time); 209 | void onChangeDuration(double time) override; 210 | 211 | void onAddingKeyPose(double time) override; 212 | void onClearKeyPoses() override; 213 | 214 | // void onSetPlayMode(); 215 | // void onSetPauseMode(); 216 | 217 | private: 218 | AnimTimelineSession session { this }; 219 | }; 220 | 221 | #endif // ANIMTIMELINE_H 222 | -------------------------------------------------------------------------------- /src/AnimTimeline/FormAnimTimeline.ui: -------------------------------------------------------------------------------- 1 | 2 | 3 | FormAnimTimeline 4 | 5 | 6 | Qt::NonModal 7 | 8 | 9 | 10 | 0 11 | 0 12 | 753 13 | 362 14 | 15 | 16 | 17 | 18 | 0 19 | 0 20 | 21 | 22 | 23 | 24 | 0 25 | 0 26 | 27 | 28 | 29 | 30 | 16777215 31 | 16777215 32 | 33 | 34 | 35 | 36 | 0 37 | 0 38 | 39 | 40 | 41 | Qt::NoFocus 42 | 43 | 44 | Form 45 | 46 | 47 | background: white 48 | 49 | 50 | 51 | 0 52 | 53 | 54 | 0 55 | 56 | 57 | 0 58 | 59 | 60 | 0 61 | 62 | 63 | 0 64 | 65 | 66 | 67 | 68 | 69 | 0 70 | 0 71 | 72 | 73 | 74 | 75 | 0 76 | 15 77 | 78 | 79 | 80 | 81 | 16777215 82 | 15 83 | 84 | 85 | 86 | background: gray 87 | 88 | 89 | QFrame::StyledPanel 90 | 91 | 92 | QFrame::Raised 93 | 94 | 95 | 0 96 | 97 | 98 | 99 | 0 100 | 101 | 102 | 2 103 | 104 | 105 | 0 106 | 107 | 108 | 2 109 | 110 | 111 | 0 112 | 113 | 114 | 115 | 116 | 117 | 0 118 | 0 119 | 120 | 121 | 122 | 123 | 0 124 | 15 125 | 126 | 127 | 128 | 129 | 80 130 | 15 131 | 132 | 133 | 134 | <html><head/><body><p><span style=" font-size:10pt; font-weight:600;">Start of playZone</span></p></body></html> 135 | 136 | 137 | false 138 | 139 | 140 | background-color: lightgreen 141 | 142 | 143 | Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter 144 | 145 | 146 | QAbstractSpinBox::NoButtons 147 | 148 | 149 | start : 150 | 151 | 152 | 2 153 | 154 | 155 | 999.000000000000000 156 | 157 | 158 | 0.000000000000000 159 | 160 | 161 | 162 | 163 | 164 | 165 | Qt::Horizontal 166 | 167 | 168 | QSizePolicy::Minimum 169 | 170 | 171 | 172 | 3 173 | 20 174 | 175 | 176 | 177 | 178 | 179 | 180 | 181 | 182 | 0 183 | 0 184 | 185 | 186 | 187 | 188 | 61 189 | 15 190 | 191 | 192 | 193 | 194 | 80 195 | 15 196 | 197 | 198 | 199 | <html><head/><body><p><span style=" font-size:10pt; font-weight:600;">End of playZone</span></p></body></html> 200 | 201 | 202 | background-color: #ff6666 203 | 204 | 205 | QAbstractSpinBox::NoButtons 206 | 207 | 208 | 209 | 210 | 211 | : end 212 | 213 | 214 | 999.000000000000000 215 | 216 | 217 | 15.000000000000000 218 | 219 | 220 | 221 | 222 | 223 | 224 | Qt::Horizontal 225 | 226 | 227 | QSizePolicy::Expanding 228 | 229 | 230 | 231 | 0 232 | 20 233 | 234 | 235 | 236 | 237 | 238 | 239 | 240 | 241 | 0 242 | 0 243 | 244 | 245 | 246 | 247 | 0 248 | 15 249 | 250 | 251 | 252 | 253 | 85 254 | 15 255 | 256 | 257 | 258 | <html><head/><body><p><span style=" font-size:10pt; font-weight:600;">Postition of cursor</span></p></body></html> 259 | 260 | 261 | Qt::LeftToRight 262 | 263 | 264 | background-color: #5555ff 265 | 266 | 267 | false 268 | 269 | 270 | Qt::AlignCenter 271 | 272 | 273 | QAbstractSpinBox::NoButtons 274 | 275 | 276 | 277 | 278 | 279 | 2 280 | 281 | 282 | 999.000000000000000 283 | 284 | 285 | 1.000000000000000 286 | 287 | 288 | 5.000000000000000 289 | 290 | 291 | 292 | 293 | 294 | 295 | Qt::Horizontal 296 | 297 | 298 | QSizePolicy::Expanding 299 | 300 | 301 | 302 | 0 303 | 20 304 | 305 | 306 | 307 | 308 | 309 | 310 | 311 | 312 | 0 313 | 0 314 | 315 | 316 | 317 | 318 | 15 319 | 15 320 | 321 | 322 | 323 | <html><head/><body><p><span style=" font-size:10pt; font-weight:600; color:#ffffff;">Insert/replace key pose on cursor</span></p></body></html> 324 | 325 | 326 | background-color:black; 327 | 328 | 329 | ... 330 | 331 | 332 | 333 | :/images/key.png:/images/key.png 334 | 335 | 336 | 337 | 15 338 | 15 339 | 340 | 341 | 342 | 343 | 344 | 345 | 346 | 347 | 0 348 | 15 349 | 350 | 351 | 352 | 353 | 35 354 | 15 355 | 356 | 357 | 358 | <html><head/><body><p><span style=" font-size:10pt; font-weight:600;">Numbers of keyPoses</span></p></body></html> 359 | 360 | 361 | false 362 | 363 | 364 | border:white; 365 | 366 | 367 | Qt::AlignCenter 368 | 369 | 370 | true 371 | 372 | 373 | QAbstractSpinBox::NoButtons 374 | 375 | 376 | 999 377 | 378 | 379 | 380 | 381 | 382 | 383 | false 384 | 385 | 386 | 387 | 0 388 | 15 389 | 390 | 391 | 392 | 393 | 20 394 | 15 395 | 396 | 397 | 398 | <html><head/><body><p><span style=" font-size:10pt; font-weight:600;">Delete keyPose on cursor</span></p></body></html> 399 | 400 | 401 | ... 402 | 403 | 404 | 405 | :/images/deleteKey.png:/images/deleteKey.png 406 | 407 | 408 | 409 | 410 | 411 | 412 | Qt::Horizontal 413 | 414 | 415 | 416 | 0 417 | 20 418 | 419 | 420 | 421 | 422 | 423 | 424 | 425 | 426 | 0 427 | 15 428 | 429 | 430 | 431 | 432 | 18 433 | 15 434 | 435 | 436 | 437 | <html><head/><body><p><span style=" font-size:10pt; font-weight:600;">Set cursor to the start</span></p></body></html> 438 | 439 | 440 | ... 441 | 442 | 443 | 444 | :/images/start.png:/images/start.png 445 | 446 | 447 | 448 | 449 | 450 | 451 | 452 | 0 453 | 15 454 | 455 | 456 | 457 | 458 | 18 459 | 15 460 | 461 | 462 | 463 | <html><head/><body><p><span style=" font-size:10pt; font-weight:600;">Set cursor to previous keyPose</span></p></body></html> 464 | 465 | 466 | ... 467 | 468 | 469 | 470 | :/images/rearward.png:/images/rearward.png 471 | 472 | 473 | 474 | 475 | 476 | 477 | 478 | 0 479 | 15 480 | 481 | 482 | 483 | 484 | 20 485 | 15 486 | 487 | 488 | 489 | <html><head/><body><p><span style=" font-size:10pt; font-weight:600;">Play/pause animation</span></p></body></html> 490 | 491 | 492 | ... 493 | 494 | 495 | 496 | :/images/play.png:/images/play.png 497 | 498 | 499 | 500 | 501 | 502 | 503 | 504 | 0 505 | 15 506 | 507 | 508 | 509 | 510 | 18 511 | 15 512 | 513 | 514 | 515 | <html><head/><body><p><span style=" font-size:10pt; font-weight:600;">Set cursor to next keyPose</span></p></body></html> 516 | 517 | 518 | ... 519 | 520 | 521 | 522 | :/images/forward.png:/images/forward.png 523 | 524 | 525 | 526 | 527 | 528 | 529 | 530 | 0 531 | 15 532 | 533 | 534 | 535 | 536 | 18 537 | 15 538 | 539 | 540 | 541 | <html><head/><body><p><span style=" font-size:10pt; font-weight:600;">Set cursor to the end</span></p></body></html> 542 | 543 | 544 | ... 545 | 546 | 547 | 548 | :/images/end.png:/images/end.png 549 | 550 | 551 | 552 | 553 | 554 | 555 | Qt::Horizontal 556 | 557 | 558 | 559 | 0 560 | 20 561 | 562 | 563 | 564 | 565 | 566 | 567 | 568 | 569 | 0 570 | 0 571 | 572 | 573 | 574 | 575 | 100 576 | 15 577 | 578 | 579 | 580 | 581 | 16777215 582 | 15 583 | 584 | 585 | 586 | <html><head/><body><p><span style=" font-size:10pt; font-weight:600;">Total duration</span></p></body></html> 587 | 588 | 589 | Qt::LeftToRight 590 | 591 | 592 | background: darkgray; 593 | 594 | 595 | Qt::AlignCenter 596 | 597 | 598 | QAbstractSpinBox::NoButtons 599 | 600 | 601 | : duration 602 | 603 | 604 | 999.000000000000000 605 | 606 | 607 | 20.000000000000000 608 | 609 | 610 | 611 | 612 | 613 | 614 | Qt::Horizontal 615 | 616 | 617 | 618 | 0 619 | 20 620 | 621 | 622 | 623 | 624 | 625 | 626 | 627 | 628 | 0 629 | 15 630 | 631 | 632 | 633 | 634 | 18 635 | 15 636 | 637 | 638 | 639 | <html><head/><body><p align="center"><span style=" font-size:24pt;">List of keybindings</span></p><p><span style=" font-size:20pt; font-weight:600; font-style:italic;">* KeyPose :</span></p><p><span style=" font-size:16pt; color:#ff5500;">Next / Previous :</span></p><p><span style=" font-weight:600;">&lt;left/right&gt;</span> or <span style=" font-weight:600;">&lt;shift&gt;+&lt;wheelMouse&gt; </span><span style=" color:#aa00ff;">(on ruler)</span> : set cursor to next / previous keyPose</p><p><span style=" font-weight:600;">&lt;wheelMouse&gt; </span><span style=" color:#aa00ff;">(over keyPose numbering spinBox)</span> : idem</p><p><span style=" font-size:16pt; color:#ff5500;">Insert / Replace :</span></p><p><span style=" font-weight:600;">&lt;i&gt;</span> : insert/replace keyPose on cursor</p><p><span style=" font-size:16pt; color:#ff5500;">Delete :</span></p><p><span style=" font-weight:600;">&lt;shift&gt;+&lt;i&gt; </span>or <span style=" font-weight:600;">&lt;del&gt;</span> : delete current keyPose</p><p><span style=" font-weight:600;">&lt;shift&gt;+&lt;leftClick&gt; </span><span style=" color:#aa00ff;">(on ruler)</span> : remove keyPoses between cursor and mouse</p><p><span style=" font-size:16pt; color:#ff5500;">Move :</span></p><p><span style=" font-size:12pt; color:#ff5500;">cursor already on keyPose :</span></p><p><span style=" font-weight:600;">&lt;rightClick&gt; </span><span style=" color:#aa00ff;">(on ruler)</span> : move current keyPose on mouse and slide its right brothers (right brothers : all keyPoses on the right of current keyPose)</p><p><span style=" font-weight:600;">&lt;shift&gt;+&lt;rightClick&gt; </span><span style=" color:#aa00ff;">(on ruler)</span> : move current keyPose on mouse click</p><p><span style=" font-size:12pt; color:#ff5500;">cursor not on keyPose :</span></p><p><span style=" font-weight:600;">&lt;rightClick&gt; </span><span style=" color:#aa00ff;">(on ruler)</span> : move first keyPose on the left of mouse on mouse and slide its right brothers</p><p><span style=" font-weight:600;">&lt;shift&gt;+&lt;rightClick&gt; </span><span style=" color:#aa00ff;">(on ruler)</span> : move first keyPose on the right of mouse on mouse and slide its right brothers</p><p><span style=" font-size:20pt; font-weight:600; font-style:italic;">* Cursor :</span></p><p><span style=" font-weight:600;">&lt;leftClick&gt; </span><span style=" color:#aa00ff;">(on ruler)</span> : move cursor and update renderer</p><p><span style=" font-weight:600;">&lt;ctrl&gt;+&lt;leftClick&gt; </span><span style=" color:#aa00ff;">(on ruler)</span> : move cursor without renderer update (need to create multiple keyPose of same skeleton, avoid auto interpolate)</p><p><span style=" font-size:20pt; font-weight:600; font-style:italic;">* Ruler :</span></p><p><span style=" font-weight:600;">&lt;wheeMouse&gt; </span><span style=" color:#aa00ff;">(on ruler)</span> : zoom in/out (<span style=" color:#00aa00;">speed of zoom can be changed, see configuration.h</span>)</p><p><span style=" font-weight:600;">&lt;ctrl&gt;+&lt;wheelMouse&gt;</span> or <span style=" font-weight:600;">&lt;hold middleClick&gt;+&lt;mouseMove&gt;</span> (<span style=" color:#aa00ff;">on ruler</span>) : slide left/right ruler (<span style=" color:#00aa00;">slide speed can be changed, see configuration.h</span>)</p><p><span style=" font-weight:600;">&lt;shift&gt;+&lt;ctrl&gt;+&lt;wheelMouse&gt;</span> : increase/decrease size of timeline (width of dialog timeline)</p><p><span style=" font-size:20pt; font-weight:600; font-style:italic;">* Others :</span></p><p><span style=" font-weight:600;">&lt;space&gt;</span> : set play/pause mode</p><p><span style=" font-weight:600;">&lt;u&gt;</span> or <span style=" font-weight:600;">&lt;ctrl&gt;+&lt;z&gt;</span> : undo</p><p><span style=" font-weight:600;">&lt;r&gt;</span> or <span style=" font-weight:600;">&lt;shift&gt;+&lt;ctrl&gt;+&lt;z&gt;</span> : redo</p><p><br/></p></body></html> 640 | 641 | 642 | background: lightgray; 643 | 644 | 645 | ... 646 | 647 | 648 | 649 | :/images/help.png:/images/help.png 650 | 651 | 652 | 653 | 654 | 655 | 656 | 657 | 658 | 659 | 660 | 0 661 | 0 662 | 663 | 664 | 665 | false 666 | 667 | 668 | background: darkgray 669 | 670 | 671 | QFrame::StyledPanel 672 | 673 | 674 | QFrame::Sunken 675 | 676 | 677 | Qt::ScrollBarAsNeeded 678 | 679 | 680 | Qt::ScrollBarAlwaysOn 681 | 682 | 683 | true 684 | 685 | 686 | 687 | 688 | 0 689 | 0 690 | 751 691 | 332 692 | 693 | 694 | 695 | 696 | 0 697 | 0 698 | 699 | 700 | 701 | 702 | 0 703 | 0 704 | 705 | 706 | 707 | 708 | 16777215 709 | 16777215 710 | 711 | 712 | 713 | 714 | 0 715 | 0 716 | 717 | 718 | 719 | 720 | 0 721 | 0 722 | 723 | 724 | 725 | 726 | 0 727 | 728 | 729 | 0 730 | 731 | 732 | 0 733 | 734 | 735 | 0 736 | 737 | 738 | 0 739 | 740 | 741 | 742 | 743 | 744 | 0 745 | 0 746 | 747 | 748 | 749 | 750 | 0 751 | 0 752 | 753 | 754 | 755 | 756 | 16777215 757 | 16777215 758 | 759 | 760 | 761 | 762 | 0 763 | 0 764 | 765 | 766 | 767 | background: lightgray; 768 | 769 | 770 | QFrame::StyledPanel 771 | 772 | 773 | QFrame::Raised 774 | 775 | 776 | 777 | 0 778 | 779 | 780 | 1 781 | 782 | 783 | 0 784 | 785 | 786 | 1 787 | 788 | 789 | 790 | 791 | background-color: rgba(0, 0, 255, 0); 792 | 793 | 794 | 795 | Qt::Horizontal 796 | 797 | 798 | 799 | 800 | 0 801 | 0 802 | 803 | 804 | 805 | background-color: rgba(0, 0, 255, 00); 806 | 807 | 808 | 809 | QFrame::StyledPanel 810 | 811 | 812 | QFrame::Raised 813 | 814 | 815 | 816 | 817 | 818 | 0 819 | 0 820 | 821 | 822 | 823 | background-color: qlineargradient(spread:pad, x1: 0 y1: 0, x2: 1 y2: 0, stop:0 rgba(0,255, 0, 40), stop:1 rgba(255, 0, 0, 40)); 824 | border: 0px; 825 | 826 | 827 | QFrame::StyledPanel 828 | 829 | 830 | QFrame::Raised 831 | 832 | 833 | 1 834 | 835 | 836 | 837 | 838 | background-color: rgba(0, 0, 255, 0); 839 | 840 | 841 | QFrame::StyledPanel 842 | 843 | 844 | QFrame::Raised 845 | 846 | 847 | 848 | 849 | 850 | 851 | 852 | 853 | 854 | 855 | 856 | 0 857 | 0 858 | 859 | 860 | 861 | 862 | 0 863 | 15 864 | 865 | 866 | 867 | 868 | 16777215 869 | 15 870 | 871 | 872 | 873 | QFrame::NoFrame 874 | 875 | 876 | QFrame::Raised 877 | 878 | 879 | 880 | 881 | 882 | 883 | 884 | 885 | 886 | 887 | 888 | QFrameSelector 889 | QFrame 890 |
AnimTimeline/qframeselector.h
891 | 1 892 | 893 | updatePlayZone(int) 894 | changeStart(double) 895 | changeCursor(double) 896 | changeEnd(double) 897 | changeNbKeyPoses(int) 898 | changePauseMode() 899 | isOnKeyPose(bool) 900 | changeCursor(double,bool) 901 | signal1() 902 | startChanged(double) 903 | endChanged(double) 904 | nbKeyPosesChanged(int) 905 | onSlideLeftSlider(int) 906 | onSlideRightSlider(int) 907 | onSlideRelease() 908 | onAddKeyPose() 909 | onPlay() 910 | onPause() 911 | onChangeStart() 912 | onChangeEnd() 913 | onSetCursorToStart() 914 | onSetCursorToEnd() 915 | onSetCursorToPreviousKeyPose() 916 | onSetCursorToNextKeyPose() 917 | onChangeStartSpin() 918 | onChangeCursorSpin() 919 | onChangeEndSpin() 920 | onAddingKeyPose() 921 | onAddingKeyPose(double) 922 | onDeleteKeyPose() 923 | onStartIncPlus() 924 | onStartIncLess() 925 | onEndIncPlus() 926 | onEndIncLess() 927 | onChangeDuration() 928 | onAddingKeyPose(double,bool) 929 | 930 |
931 | 932 | QWidgetRuler 933 | QWidget 934 |
AnimTimeline/qwidgetruler.h
935 | 1 936 |
937 | 938 | QScrollAreaRuler 939 | QScrollArea 940 |
AnimTimeline/qscrollarearuler.h
941 | 1 942 | 943 | addKeyPose() 944 | removeKeyPose() 945 | adKeyPose(double,bool) 946 | nextKeyPose() 947 | previousKeyPose() 948 | onPlayPause() 949 | 950 |
951 | 952 | QFrameTimescale 953 | QFrame 954 |
AnimTimeline/qframetimescale.h
955 | 1 956 |
957 | 958 | QToolButtonPlayPause 959 | QToolButton 960 |
AnimTimeline/qtoolbuttonplaypause.h
961 | 962 | playClicked() 963 | pauseClicked() 964 | onPauseMode() 965 | 966 |
967 | 968 | QFrameButtons 969 | QFrame 970 |
AnimTimeline/qframebuttons.h
971 | 1 972 | 973 | helpClicked() 974 | 975 |
976 | 977 | QDoubleSpinBoxSmart 978 | QDoubleSpinBox 979 |
AnimTimeline/qdoublespinboxsmart.h
980 |
981 | 982 | QSpinBoxSmart 983 | QSpinBox 984 |
AnimTimeline/qspinboxsmart.h
985 |
986 |
987 | 988 | 989 | 990 | 991 | 992 | render(double) 993 | onCursorChanged(double) 994 | onKeyPose(bool) 995 | onCursorChanged(double,bool) 996 | 997 |
998 | -------------------------------------------------------------------------------- /src/AnimTimeline/QWidgetSlider.cpp: -------------------------------------------------------------------------------- 1 | //#include 2 | //#include "qlabelslider.h" 3 | #include "QWidgetSlider.h" 4 | 5 | #include 6 | 7 | QWidgetSlider::QWidgetSlider(QWidget* parent) 8 | // : QLabel(parent) 9 | : QWidget(parent) 10 | { 11 | } 12 | 13 | void QWidgetSlider::mousePressEvent(QMouseEvent* event) 14 | { 15 | if (event->button() == Qt::LeftButton) { 16 | clicked = true; 17 | emit slide(event->x()); 18 | } 19 | } 20 | 21 | void QWidgetSlider::mouseReleaseEvent(QMouseEvent* event) 22 | { 23 | if (event->button() == Qt::LeftButton) { 24 | setStyleSheet("background-color: gray"); 25 | 26 | clicked = false; 27 | emit slideRelease(); 28 | } 29 | } 30 | 31 | void QWidgetSlider::mouseMoveEvent(QMouseEvent* event) 32 | { 33 | if (clicked) { 34 | emit slide(event->x()); 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /src/AnimTimeline/QWidgetSlider.h: -------------------------------------------------------------------------------- 1 | #ifndef QLABELSLIDER_H 2 | #define QLABELSLIDER_H 3 | 4 | //#include 5 | #include 6 | 7 | //class QLabelSlider : public QLabel { 8 | class QWidgetSlider : public QWidget { 9 | Q_OBJECT 10 | public: 11 | explicit QWidgetSlider(QWidget* parent = nullptr); 12 | 13 | protected: 14 | void mousePressEvent(QMouseEvent* event) override; 15 | void mouseReleaseEvent(QMouseEvent* event) override; 16 | void mouseMoveEvent(QMouseEvent* event) override; 17 | 18 | signals: 19 | void slide(int deltaX); 20 | void slideRelease(); 21 | 22 | public slots: 23 | 24 | private: 25 | int x; 26 | bool clicked = false; 27 | 28 | bool align[3]; 29 | }; 30 | 31 | #endif // QLABELSLIDER_H 32 | -------------------------------------------------------------------------------- /src/AnimTimeline/configurations.h: -------------------------------------------------------------------------------- 1 | #ifndef CONFIGURATIONS_H 2 | #define CONFIGURATIONS_H 3 | 4 | 5 | namespace AnimTimeline { 6 | 7 | // fix timeline's width directly in animtimeline.ui 8 | 9 | // first timeline position is fixed at startup with these margins (right/bottom) 10 | // parent area : 11 | // --------------------------------- 12 | // | | 13 | // | | 14 | // | | 15 | // | | 16 | // | ------------ | 17 | // | | timeline | <---> | 18 | // | ------------ | 19 | // | | 20 | // | | 21 | // | | 22 | // --------------------------------- 23 | const unsigned int MARGIN_RIGHT = 50; // unit : pixel 24 | // --------------------------------- 25 | // | | 26 | // | | 27 | // | | 28 | // | | 29 | // | ------------ | 30 | // | | timeline | | 31 | // | ------------ | 32 | // | ^ | 33 | // | | | 34 | // | v | 35 | // --------------------------------- 36 | const unsigned int MARGIN_DOWN = 40; // unit : pixel 37 | 38 | // ----------------------- ----------------------- 39 | // | | timeline || | | | timeline || | 40 | // ----------------------- ----------------------- 41 | // ^ ^ <-- 42 | // | | 43 | // cursor cursor 44 | // on ruler clicking, automove to nearest keyPose or ruler scale 45 | // if the distance with cursor is below this constant 46 | const unsigned int AUTO_SUGGEST_CURSOR_RADIUS = 4; // unit : pixel 47 | 48 | // zoom in/out speed factor ( on ruler) 49 | const double ZOOM_SPEED = 1.0; // unit : double (0.0 .. oo) 50 | 51 | // slide ruler speed factor ( + on ruler) 52 | const double SLIDE_SPEED = 1.0; // unit : double (0.0 .. oo) 53 | 54 | // todo : maybe set global static var 55 | // frame per second to draw position of each frame in ruler 56 | const double FPS = 24.0; 57 | 58 | const unsigned int BUFFER_SESSION_MAX_SIZE =500000000; // 500M bytes in RAM, max bytes for saving user anim for undo/redo stack 59 | 60 | const unsigned int DELAY_AUTO_SAVE =100; // millisecond, auto save environment after delay 61 | 62 | } 63 | 64 | #endif // CONFIGURATIONS_H 65 | -------------------------------------------------------------------------------- /src/AnimTimeline/images/deleteKey.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hiergaut/AnimTimeline/1998ba097628106607888c4f0871173fe6f281a1/src/AnimTimeline/images/deleteKey.png -------------------------------------------------------------------------------- /src/AnimTimeline/images/deleteKey.xcf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hiergaut/AnimTimeline/1998ba097628106607888c4f0871173fe6f281a1/src/AnimTimeline/images/deleteKey.xcf -------------------------------------------------------------------------------- /src/AnimTimeline/images/end.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hiergaut/AnimTimeline/1998ba097628106607888c4f0871173fe6f281a1/src/AnimTimeline/images/end.png -------------------------------------------------------------------------------- /src/AnimTimeline/images/end.xcf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hiergaut/AnimTimeline/1998ba097628106607888c4f0871173fe6f281a1/src/AnimTimeline/images/end.xcf -------------------------------------------------------------------------------- /src/AnimTimeline/images/forward.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hiergaut/AnimTimeline/1998ba097628106607888c4f0871173fe6f281a1/src/AnimTimeline/images/forward.png -------------------------------------------------------------------------------- /src/AnimTimeline/images/forward.xcf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hiergaut/AnimTimeline/1998ba097628106607888c4f0871173fe6f281a1/src/AnimTimeline/images/forward.xcf -------------------------------------------------------------------------------- /src/AnimTimeline/images/help.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hiergaut/AnimTimeline/1998ba097628106607888c4f0871173fe6f281a1/src/AnimTimeline/images/help.png -------------------------------------------------------------------------------- /src/AnimTimeline/images/help.xcf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hiergaut/AnimTimeline/1998ba097628106607888c4f0871173fe6f281a1/src/AnimTimeline/images/help.xcf -------------------------------------------------------------------------------- /src/AnimTimeline/images/key.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hiergaut/AnimTimeline/1998ba097628106607888c4f0871173fe6f281a1/src/AnimTimeline/images/key.png -------------------------------------------------------------------------------- /src/AnimTimeline/images/key.xcf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hiergaut/AnimTimeline/1998ba097628106607888c4f0871173fe6f281a1/src/AnimTimeline/images/key.xcf -------------------------------------------------------------------------------- /src/AnimTimeline/images/leftSlider.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hiergaut/AnimTimeline/1998ba097628106607888c4f0871173fe6f281a1/src/AnimTimeline/images/leftSlider.png -------------------------------------------------------------------------------- /src/AnimTimeline/images/less.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hiergaut/AnimTimeline/1998ba097628106607888c4f0871173fe6f281a1/src/AnimTimeline/images/less.png -------------------------------------------------------------------------------- /src/AnimTimeline/images/less.xcf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hiergaut/AnimTimeline/1998ba097628106607888c4f0871173fe6f281a1/src/AnimTimeline/images/less.xcf -------------------------------------------------------------------------------- /src/AnimTimeline/images/pause.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hiergaut/AnimTimeline/1998ba097628106607888c4f0871173fe6f281a1/src/AnimTimeline/images/pause.png -------------------------------------------------------------------------------- /src/AnimTimeline/images/pause.xcf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hiergaut/AnimTimeline/1998ba097628106607888c4f0871173fe6f281a1/src/AnimTimeline/images/pause.xcf -------------------------------------------------------------------------------- /src/AnimTimeline/images/play.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hiergaut/AnimTimeline/1998ba097628106607888c4f0871173fe6f281a1/src/AnimTimeline/images/play.png -------------------------------------------------------------------------------- /src/AnimTimeline/images/play.xcf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hiergaut/AnimTimeline/1998ba097628106607888c4f0871173fe6f281a1/src/AnimTimeline/images/play.xcf -------------------------------------------------------------------------------- /src/AnimTimeline/images/plus.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hiergaut/AnimTimeline/1998ba097628106607888c4f0871173fe6f281a1/src/AnimTimeline/images/plus.png -------------------------------------------------------------------------------- /src/AnimTimeline/images/plus.xcf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hiergaut/AnimTimeline/1998ba097628106607888c4f0871173fe6f281a1/src/AnimTimeline/images/plus.xcf -------------------------------------------------------------------------------- /src/AnimTimeline/images/rearward.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hiergaut/AnimTimeline/1998ba097628106607888c4f0871173fe6f281a1/src/AnimTimeline/images/rearward.png -------------------------------------------------------------------------------- /src/AnimTimeline/images/rearward.xcf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hiergaut/AnimTimeline/1998ba097628106607888c4f0871173fe6f281a1/src/AnimTimeline/images/rearward.xcf -------------------------------------------------------------------------------- /src/AnimTimeline/images/rightSlider.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hiergaut/AnimTimeline/1998ba097628106607888c4f0871173fe6f281a1/src/AnimTimeline/images/rightSlider.png -------------------------------------------------------------------------------- /src/AnimTimeline/images/start.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hiergaut/AnimTimeline/1998ba097628106607888c4f0871173fe6f281a1/src/AnimTimeline/images/start.png -------------------------------------------------------------------------------- /src/AnimTimeline/images/start.xcf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hiergaut/AnimTimeline/1998ba097628106607888c4f0871173fe6f281a1/src/AnimTimeline/images/start.xcf -------------------------------------------------------------------------------- /src/AnimTimeline/qdoublespinboxsmart.cpp: -------------------------------------------------------------------------------- 1 | //#include 2 | #include "qdoublespinboxsmart.h" 3 | 4 | #include 5 | #include 6 | 7 | QDoubleSpinBoxSmart::QDoubleSpinBoxSmart(QWidget* parent) 8 | : QDoubleSpinBox(parent) 9 | { 10 | } 11 | 12 | void QDoubleSpinBoxSmart::wheelEvent(QWheelEvent* event) 13 | { 14 | QDoubleSpinBox::wheelEvent(event); 15 | 16 | emit editingFinished(); 17 | 18 | event->accept(); 19 | } 20 | 21 | void QDoubleSpinBoxSmart::keyPressEvent(QKeyEvent* event) 22 | { 23 | // qDebug() << "QDoubleSpinBoxSmart::keyPressEvent(" << event << ")"; 24 | 25 | QDoubleSpinBox::keyPressEvent(event); 26 | switch (event->key()) { 27 | case Qt::Key_Up: 28 | case Qt::Key_Down: 29 | emit editingFinished(); 30 | break; 31 | } 32 | 33 | event->ignore(); // Esc 34 | } 35 | -------------------------------------------------------------------------------- /src/AnimTimeline/qdoublespinboxsmart.h: -------------------------------------------------------------------------------- 1 | #ifndef QDOUBLESPINBOXSMART_H 2 | #define QDOUBLESPINBOXSMART_H 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | 10 | class QDoubleSpinBoxSmart : public QDoubleSpinBox { 11 | Q_OBJECT 12 | public: 13 | explicit QDoubleSpinBoxSmart(QWidget* parent = nullptr); 14 | 15 | protected: 16 | void keyPressEvent(QKeyEvent* event) override; 17 | void wheelEvent(QWheelEvent* event) override; 18 | }; 19 | 20 | #endif // QDOUBLESPINBOXSMART_H 21 | -------------------------------------------------------------------------------- /src/AnimTimeline/qframebuttons.cpp: -------------------------------------------------------------------------------- 1 | //#include 2 | #include "qframebuttons.h" 3 | 4 | #include 5 | #include 6 | #include 7 | 8 | QFrameButtons::QFrameButtons(QWidget* parent) 9 | : QFrame(parent) 10 | { 11 | } 12 | 13 | void QFrameButtons::setRuler(QWidgetRuler* value) 14 | { 15 | ruler = value; 16 | } 17 | 18 | void QFrameButtons::keyPressEvent(QKeyEvent* event) 19 | { 20 | emit keyPressed(event); 21 | } 22 | 23 | void QFrameButtons::keyReleaseEvent(QKeyEvent* event) 24 | { 25 | emit keyReleased(event); 26 | } 27 | 28 | void QFrameButtons::setAnimTimeline(FormAnimTimeline* value) 29 | { 30 | animTimeline = value; 31 | } 32 | 33 | void QFrameButtons::helpClicked() 34 | { 35 | QMessageBox msgBox; 36 | msgBox.setText(helpButton->toolTip()); 37 | msgBox.exec(); 38 | } 39 | 40 | void QFrameButtons::setHelpButton(QToolButton* value) 41 | { 42 | helpButton = value; 43 | } 44 | 45 | void QFrameButtons::setScrollArea(QScrollArea* value) 46 | { 47 | scrollArea = value; 48 | } 49 | -------------------------------------------------------------------------------- /src/AnimTimeline/qframebuttons.h: -------------------------------------------------------------------------------- 1 | #ifndef QFRAMEBUTTONS_H 2 | #define QFRAMEBUTTONS_H 3 | 4 | //#include 5 | #include "FormAnimTimeline.h" 6 | //#include 7 | #include "qwidgetruler.h" 8 | 9 | #include 10 | #include 11 | #include 12 | #include 13 | 14 | class QFrameButtons : public QFrame { 15 | Q_OBJECT 16 | public: 17 | explicit QFrameButtons(QWidget* parent = nullptr); 18 | 19 | void setAnimTimeline(FormAnimTimeline* value); 20 | void setRuler(QWidgetRuler* value); 21 | void setScrollArea(QScrollArea* value); 22 | void setHelpButton(QToolButton* value); 23 | 24 | protected: 25 | void keyPressEvent(QKeyEvent* event) override; 26 | void keyReleaseEvent(QKeyEvent* event) override; 27 | 28 | signals: 29 | void keyPressed(QKeyEvent* event); 30 | void keyReleased(QKeyEvent* event); 31 | 32 | public slots: 33 | void helpClicked(); 34 | 35 | private: 36 | FormAnimTimeline* animTimeline; 37 | QWidgetRuler* ruler; 38 | QPoint offset; 39 | QScrollArea* scrollArea; 40 | 41 | QToolButton* helpButton; 42 | bool clicked = false; 43 | 44 | bool align[7]; 45 | }; 46 | 47 | #endif // QFRAMEBUTTONS_H 48 | -------------------------------------------------------------------------------- /src/AnimTimeline/qframeselector.cpp: -------------------------------------------------------------------------------- 1 | //#include 2 | #include "FormAnimTimeline.h" 3 | //#include 4 | #include "qframeselector.h" 5 | 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | 12 | QFrameSelector::QFrameSelector(QWidget* parent) 13 | : QFrame(parent) 14 | { 15 | widgetRuler = static_cast(parent); 16 | nbInterval = widgetRuler->getNbInterval(); 17 | step = widgetRuler->getStep(); 18 | pixPerSec = widgetRuler->getPixPerSec(); 19 | zero = widgetRuler->getZero(); 20 | duration = widgetRuler->getMaxDuration(); 21 | 22 | timer = new QTimer(this); 23 | connect(timer, SIGNAL(timeout()), this, SLOT(update())); 24 | // qDebug() << "end construct frameSelector, parent : " << parent; 25 | } 26 | 27 | QFrameSelector::~QFrameSelector() 28 | { 29 | delete timer; 30 | } 31 | 32 | double QFrameSelector::nearestStep(double time) const 33 | { 34 | double deltaT = AnimTimeline::AUTO_SUGGEST_CURSOR_RADIUS / *pixPerSec; 35 | 36 | double minDist = durationSpin->maximum(); 37 | double dist; 38 | 39 | double newCursor = time; 40 | 41 | for (double keyPose : keyPoses) { 42 | dist = qAbs(keyPose - time); 43 | if (dist < deltaT && dist < minDist) { 44 | 45 | minDist = dist; 46 | newCursor = keyPose; 47 | } 48 | if (time < keyPose) 49 | break; 50 | } 51 | 52 | for (int i = 0; i < *nbInterval - 1; ++i) { 53 | double pos = i * *step; 54 | dist = qAbs(pos - time); 55 | if (dist < deltaT && dist < minDist) { 56 | minDist = dist; 57 | newCursor = pos; 58 | } 59 | 60 | pos = i * *step + 0.5 * *step; 61 | dist = qAbs(pos - time); 62 | if (dist < deltaT && dist < minDist) { 63 | minDist = dist; 64 | newCursor = pos; 65 | } 66 | 67 | if (time < pos) 68 | break; 69 | } 70 | 71 | return newCursor; 72 | } 73 | 74 | // ------------------------------- PROTECTED ---------------------------------- 75 | void QFrameSelector::paintEvent(QPaintEvent*) 76 | { 77 | int w = width(); 78 | int h = height(); 79 | 80 | if (m_rulerChanged) { 81 | leftSpacer->setMinimumWidth(static_cast(*zero) - 3); 82 | rightSpacer->setMinimumWidth(w - (*zero + *duration * *pixPerSec) - 4); 83 | // leftSpacer->resize(200, 0); 84 | redrawPlayZone(); 85 | 86 | prepareBackground(w, h); 87 | 88 | m_rulerChanged = false; 89 | } 90 | // m_rulerChanged = true; 91 | // m_pixmapBackground.fill(Qt::red); 92 | // qDebug() << "QFrameSelector::paintEvent"; 93 | // m_pixmapBackground = new QPixmap; 94 | // QPainter painter(m_pixmapBackground); 95 | // painter.drawText(100, 100, "fuck"); 96 | QPainter painter(this); 97 | 98 | // DRAW CURSOR 99 | painter.setPen(QPen(QColor(0, 0, 255, 255), 3)); 100 | int xCursor = static_cast(*zero + cursor * *pixPerSec); 101 | painter.drawLine(xCursor, 0, xCursor, h); 102 | 103 | // DRAW KEYPOSES 104 | painter.setPen(QPen(QColor(255, 255, 0, 255), 3)); 105 | // int hTemp = h / 4 + 2; 106 | int hTemp = 3 *h / 8; 107 | for (double keyPose : keyPoses) { 108 | int xKeyPose = static_cast(*zero + keyPose * *pixPerSec); 109 | painter.drawLine(xKeyPose, hTemp, xKeyPose, h); 110 | // painter.drawLine(xKeyPose, 0, xKeyPose, hTemp); 111 | } 112 | 113 | if (updateKeyPoseFlash > 0) { 114 | 115 | if (updateKeyPoseFlash % 2 == 0) { 116 | painter.setPen(QPen(QColor(0, 0, 255, 255), 3)); 117 | int xKeyPose = static_cast(*zero + keyPoseFlash * *pixPerSec); 118 | painter.drawLine(xKeyPose, hTemp, xKeyPose, h); 119 | } 120 | 121 | if (--updateKeyPoseFlash == 0) 122 | timer->stop(); 123 | } 124 | 125 | painter.drawPixmap(rect(), *m_pixmapBackground); 126 | // return; 127 | 128 | // m_rulerChanged = false; 129 | // } else { 130 | // qDebug() << "QFrameSelector::paintEvent rulerChanged" << paintCounter; 131 | // } 132 | } 133 | 134 | //void QFrameSelector::resizeEvent(QResizeEvent* event) 135 | //{ 136 | //// qDebug() << "QFrameSelector::resizeEvent " << event; 137 | // QSize size = event->size(); 138 | // int w = size.width(); 139 | // int h = size.height(); 140 | //} 141 | 142 | void QFrameSelector::mousePressEvent(QMouseEvent* event) 143 | { 144 | // ---------------------- LEFT CLICK -------------------------------------- 145 | if (event->button() == Qt::LeftButton) { 146 | double newCursor = qMax((event->x() - *zero) / *pixPerSec, 0.0); 147 | 148 | // move cursor without render 149 | if (*ctrlDown) { 150 | onChangeCursor(newCursor, false); 151 | } 152 | // delete keyPoses between cursor and newCursor 153 | else if (*shiftDown) { 154 | deleteZone(cursor, newCursor); 155 | } 156 | // move cursor and update renderer 157 | else { 158 | onChangeCursor(newCursor); 159 | mouseLeftClicked = true; 160 | } 161 | 162 | // ------------------ RIGHT CLICK ------------------------------------- 163 | } else if (event->button() == Qt::RightButton) { 164 | double newPose = qMax((event->x() - *zero) / *pixPerSec, 0.0); 165 | 166 | auto it = keyPoses.find(cursor); 167 | 168 | // if already on keyPose, move current keyPose 169 | // ------------------- CURSOR ON KEYPOSE ----------------------- 170 | if (it != keyPoses.end()) { 171 | 172 | double nearest = nearestStep(newPose); 173 | // -------------- SINGLE MOVE ------------------------------------- 174 | if (*shiftDown) { 175 | // if no keyPose under mouse, move keyPose to newPose 176 | if (keyPoses.find(nearest) == keyPoses.end()) { 177 | 178 | if (qAbs(cursor - nearest) > 1e-5) { 179 | cursor = nearest; 180 | 181 | size_t id = static_cast(std::distance(keyPoses.begin(), it)); 182 | keyPoses.erase(it); 183 | keyPoses.insert(cursor); 184 | 185 | updateCursorSpin(); // to find keyPose here, yellow spinBox 186 | update(); 187 | 188 | emit keyPoseMoved(id, cursor); // EXTERNAL SIGNAL 189 | qDebug() << "\033[35mkeyPoseMoved(" << id << ", " << cursor << ")\033[0m"; 190 | } 191 | } 192 | 193 | // ---------- MULTIPLE MOVE ----------------------------------- 194 | } else { 195 | auto itLeft = it; 196 | --itLeft; 197 | double left = (it == keyPoses.begin()) ? (0.0) : (*itLeft); 198 | 199 | if (nearest > left) { 200 | double dist = nearest - cursor; 201 | size_t id = static_cast(std::distance(keyPoses.begin(), it)); 202 | moveKeyPoses(dist, id); 203 | } 204 | } 205 | 206 | // ---------------- CURSOR NOT ON KEYPOSE -------------------------- 207 | } else { 208 | 209 | // if shiftdown, slide first right keypose to the left 210 | // --------------- MOVE RIGHT KEYPOSE TO THE LEFT ----------------- 211 | if (*shiftDown) { 212 | auto it = keyPoses.begin(); 213 | size_t iRight = 0; 214 | while (it != keyPoses.end() && *it < newPose) { 215 | ++it; 216 | ++iRight; 217 | } 218 | 219 | // if keyPoses on the right, remove or insert time 220 | if (it != keyPoses.end()) { 221 | 222 | double right = *it; 223 | double dist = newPose - right; 224 | moveKeyPoses(dist, iRight); 225 | } 226 | 227 | // if not shiftdown, slide first left keypose to the right 228 | // ---------------- MOVE LEFT KEYPOSE TO THE RIGHT ----------- 229 | } else { 230 | auto it = keyPoses.rbegin(); 231 | size_t iLeft = keyPoses.size() - 1; 232 | while (it != keyPoses.rend() && *it > newPose) { 233 | ++it; 234 | --iLeft; 235 | } 236 | 237 | if (it != keyPoses.rend()) { 238 | double left = *it; 239 | double dist = newPose - left; 240 | 241 | moveKeyPoses(dist, iLeft); 242 | } 243 | } 244 | } 245 | 246 | // no catch mouse event 247 | } else { 248 | event->ignore(); 249 | return; 250 | } 251 | event->accept(); 252 | } 253 | 254 | void QFrameSelector::mouseMoveEvent(QMouseEvent* event) 255 | { 256 | if (mouseLeftClicked) { 257 | double newCursor = qMax((event->x() - *zero) / *pixPerSec, 0.0); 258 | 259 | onChangeCursor(newCursor); 260 | } else { 261 | event->ignore(); 262 | } 263 | } 264 | 265 | void QFrameSelector::mouseReleaseEvent(QMouseEvent* event) 266 | { 267 | if (event->button() == Qt::LeftButton) { 268 | mouseLeftClicked = false; 269 | event->accept(); 270 | 271 | } else { 272 | event->ignore(); 273 | } 274 | } 275 | 276 | // -------------------------- EXTERNAL SLOTS ---------------------------------- 277 | // EXTERNAL SLOT 278 | void QFrameSelector::onAddingKeyPose(double time, bool internal /* = true */) 279 | { 280 | // by default (time = -1.0), add keyPose on cursor 281 | if (static_cast(time) == -1) 282 | time = cursor; 283 | 284 | int nbKeyPoses = static_cast(keyPoses.size()); 285 | keyPoses.insert(time); 286 | 287 | // if keyPose not already here 288 | if (static_cast(keyPoses.size()) != nbKeyPoses) { 289 | updateCursorSpin(); 290 | update(); 291 | 292 | if (internal) { 293 | emit keyPoseAdded(time); // EXTERNAL SIGNAL 294 | qDebug() << "\033[35mkeyPoseAdded(" << time << ")\033[0m"; 295 | } 296 | 297 | nbKeyPosesSpin->setValue(static_cast(keyPoses.size())); 298 | 299 | // keyPose already here, change actual keyPose 300 | } else { 301 | auto it = keyPoses.find(time); 302 | size_t id = static_cast(std::distance(keyPoses.begin(), it)); 303 | 304 | if (internal) { 305 | emit keyPoseChanged(id); // EXTERNAL SIGNAL 306 | qDebug() << "\033[35mkeyPoseChanged(" << id << ")\033[0m"; 307 | } 308 | 309 | updateKeyPoseFlash = 6; 310 | keyPoseFlash = time; 311 | 312 | timer->start(50); 313 | 314 | update(); 315 | } 316 | } 317 | 318 | // EXTERNAL SLOT 319 | void QFrameSelector::onClearKeyPoses() 320 | { 321 | keyPoses.clear(); 322 | nbKeyPosesSpin->setValue(0); 323 | 324 | updateCursorSpin(); 325 | update(); 326 | } 327 | 328 | // EXTERNAL SLOT 329 | void QFrameSelector::onChangeStart(double time, bool internal /* = true */) 330 | { 331 | double newStart = qMax(qMin(time, end), 0.0); 332 | 333 | bool out = qAbs(newStart - time) > 1e-5; 334 | bool change = qAbs(newStart - start) > 1e-5; 335 | 336 | if (change) { 337 | start = newStart; 338 | updateStartSpin(); 339 | redrawPlayZone(); 340 | 341 | // emit signal if time of emitter is internal changed due of limits 342 | if (internal || out) { 343 | emit startChanged(start); // EXTERNAL SIGNAL 344 | qDebug() << "\033[35mstartChanged(" << start << ")\033[0m"; 345 | } 346 | } else { 347 | 348 | if (out) { 349 | updateStartSpin(); 350 | } 351 | } 352 | } 353 | 354 | // EXTERNAL SLOT 355 | void QFrameSelector::onChangeEnd(double time, bool internal /* = true */) 356 | { 357 | double newEnd = qMin(qMax(time, start), *duration); 358 | 359 | bool out = qAbs(newEnd - time) > 1e-5; 360 | bool change = qAbs(newEnd - end) > 1e-5; 361 | 362 | // emit signal only if new value of end 363 | if (change) { 364 | end = newEnd; 365 | updateEndSpin(); 366 | redrawPlayZone(); 367 | // update(); 368 | 369 | if (internal || out) { 370 | emit endChanged(end); // EXTERNAL SIGNAL 371 | qDebug() << "\033[35mendChanged(" << end << ")\033[0m"; 372 | } 373 | } else { 374 | 375 | if (out) { 376 | updateEndSpin(); 377 | } 378 | } 379 | } 380 | 381 | // EXTERNAL SLOT (warning on using EXTERNAL SIGNAL) 382 | void QFrameSelector::onChangeCursor(double time, bool internal /* = true */) 383 | { 384 | double newCursor = qMax(0.0, time); 385 | 386 | if (internal) { 387 | newCursor = nearestStep(newCursor); 388 | } 389 | 390 | bool out = qAbs(newCursor - time) > 1e-5; 391 | bool change = qAbs(newCursor - cursor) > 1e-5; 392 | 393 | if (change) { 394 | cursor = newCursor; 395 | updateCursorSpin(); 396 | // redrawPlayZone(); 397 | update(); 398 | 399 | if (internal || out) { 400 | emit cursorChanged(cursor); // EXTERNAL SIGNAL 401 | qDebug() << "\033[35mcursorChanged(" << time << ")\033[0m"; 402 | } 403 | } else { 404 | 405 | if (out) { 406 | updateCursorSpin(); 407 | } 408 | } 409 | } 410 | 411 | // EXTERNAL SLOT 412 | void QFrameSelector::onChangeDuration(double time, bool internal /* = true */) 413 | { 414 | double newDuration = qMax(time, 0.0); 415 | 416 | bool out = qAbs(newDuration - time) > 1e-5; 417 | bool change = qAbs(newDuration - *duration) > 1e-5; 418 | 419 | if (change) { 420 | *duration = newDuration; 421 | widgetRuler->drawRuler(widgetRuler->minimumWidth()); 422 | updateDurationSpin(); 423 | // redrawPlayZone(); 424 | 425 | // emit signal if time of emitter is internal changed due of limits 426 | if (internal || out) { 427 | emit durationChanged(*duration); 428 | qDebug() << "\033[35mdurationChanged(" << *duration << ")\033[0m"; 429 | } 430 | } else { 431 | 432 | if (out) { 433 | updateDurationSpin(); 434 | } 435 | } 436 | 437 | if (*duration < start) 438 | onChangeStart(*duration); 439 | 440 | if (*duration < end) 441 | onChangeEnd(*duration); 442 | 443 | // auto update 444 | } 445 | 446 | void QFrameSelector::prepareBackground(int w, int h) 447 | { 448 | if (m_pixmapBackground != nullptr) 449 | delete m_pixmapBackground; 450 | m_pixmapBackground = new QPixmap(this->size()); 451 | m_pixmapBackground->fill(QColor(255, 255, 255, 0)); 452 | // m_pixmapBackground->fill(QColor(255, 0, 0, 255)); 453 | 454 | QPainter painter(m_pixmapBackground); 455 | // int h = height; 456 | // int w = width; 457 | // painter.begin(this); 458 | // painter.drawText(100, 100, "fuck"); 459 | // painter.end(); 460 | 461 | // if (!sliding) { 462 | // redrawPlayZone(); 463 | // } 464 | 465 | // DRAW FRAME SCALE 466 | // painter.setPen(QPen(Qt::lightGray)); 467 | painter.setPen(QPen(QColor(127, 127, 127, 64), 1)); 468 | double frameDuration = 1.0 / AnimTimeline::FPS; 469 | int hUp = h / 3; 470 | double nbFrame = *duration / frameDuration; 471 | for (int i = 0; i < nbFrame; i++) { 472 | int x = static_cast(i * frameDuration * *pixPerSec + *zero); 473 | painter.drawLine(x, 0, x, hUp); 474 | } 475 | 476 | // DRAW TIME SCALE 477 | // int hDown = 2 * h / 3; 478 | int hDown = h / 2; 479 | painter.setPen(Qt::black); 480 | for (int i = 1; i < *nbInterval; i++) { 481 | int x = static_cast(i * *step * *pixPerSec); 482 | painter.drawLine(x, hDown, x, h); 483 | } 484 | int hDown2 = 3 * h / 4; 485 | painter.setPen(Qt::darkGray); 486 | for (int i = 1; i < *nbInterval - 1; i++) { 487 | int middle = static_cast((i + 0.5) * *step * *pixPerSec); 488 | painter.drawLine(middle, hDown2, middle, h); 489 | } 490 | 491 | // DRAW MIDDLE RULER SEPARATOR 492 | // int gap = h / 15; 493 | // painter.setPen(Qt::white); 494 | // // painter.drawLine(0, h / 2 + gap + 2, w, h / 2 + gap + 2); 495 | // painter.drawLine(0, h / 2 + gap + 1, w, h / 2 + gap + 1); 496 | 497 | // painter.setPen(Qt::darkGray); 498 | // painter.drawLine(0, h / 2 + gap, w, h / 2 + gap); 499 | 500 | // painter.setPen(Qt::black); 501 | // painter.drawLine(0, h / 2 - gap - 1, w, h / 2 - gap - 1); 502 | // // painter.drawLine(0, h / 2 - gap - 2, w, h / 2 - gap - 2); 503 | 504 | // QRect rect(0, h / 2 - gap, w, gap + gap / 3); 505 | // QLinearGradient gradient(0, rect.top(), 0, rect.bottom()); 506 | // gradient.setColorAt(0, QColor(128, 128, 128, 127)); 507 | // gradient.setColorAt(1, QColor(255, 255, 255, 255)); 508 | // painter.fillRect(rect, gradient); 509 | 510 | // QRect rect2(0, h / 2 + gap / 3, w, 2 * gap / 3 + 1); 511 | // QLinearGradient gradient2(0, rect2.top(), 0, rect2.bottom()); 512 | // gradient2.setColorAt(0, QColor(255, 255, 255, 255)); 513 | // gradient2.setColorAt(1, QColor(192, 192, 192, 127)); 514 | // painter.fillRect(rect2, gradient2); 515 | } 516 | 517 | void QFrameSelector::onRulerChange() 518 | { 519 | m_rulerChanged = true; 520 | } 521 | 522 | // -------------------------- INTERNAL SLOTS ---------------------------------- 523 | void QFrameSelector::onSlideLeftSlider(int deltaX) 524 | { 525 | // qDebug() << "QFrameSelector::onSlideLeftSlider " << deltaX; 526 | 527 | // if (!sliding) { 528 | //// leftSlider->setStyleSheet("background-color: #00ff00"); 529 | // sliding = true; 530 | // } 531 | 532 | // double newStart = start + deltaX / *pixPerSec; 533 | double newStart = (deltaX - *zero) / *pixPerSec; 534 | 535 | onChangeStart(newStart); // EXTERNAL SLOT 536 | 537 | // leftSpacer->setMinimumWidth(static_cast(*zero + start * *pixPerSec)); 538 | // leftSpacer->setMinimumWidth(static_cast(*zero) - 3); 539 | // playZone->setMinimumWidth(static_cast((end - start) * *pixPerSec)); 540 | } 541 | 542 | void QFrameSelector::onSlideRightSlider(int deltaX) 543 | { 544 | // qDebug() << "QFrameSelector::onSlideRightSlider " << deltaX; 545 | 546 | // if (!sliding) { 547 | //// rightSlider->setStyleSheet("background-color: red"); 548 | // sliding = true; 549 | // } 550 | // double newEnd = end + deltaX / *pixPerSec; 551 | double newEnd = (deltaX - *zero) / *pixPerSec; 552 | 553 | onChangeEnd(newEnd); // EXTERNAL SLOT 554 | 555 | // playZone->setMinimumWidth(static_cast((end - start) * *pixPerSec)); 556 | // rightSpacer->setMinimumWidth(width() - (*zero + *duration * *pixPerSec) - 3); 557 | } 558 | 559 | //void QFrameSelector::onLeftSlideRelease() 560 | //{ 561 | // // sliding = false; 562 | //} 563 | 564 | //void QFrameSelector::onRightSlideRelease() 565 | //{ 566 | // // sliding = false; 567 | //} 568 | 569 | void QFrameSelector::onSplitterMove(int pos, int index) 570 | { 571 | // qDebug() << "QFrameSelector::splitterMove " << pos << index; 572 | if (index == 1) { 573 | onSlideLeftSlider(pos); 574 | } else { 575 | onSlideRightSlider(pos); 576 | } 577 | } 578 | 579 | void QFrameSelector::onDeleteKeyPose() 580 | { 581 | auto it = keyPoses.find(cursor); 582 | 583 | if (it != keyPoses.end()) { 584 | 585 | size_t id = static_cast(std::distance(keyPoses.begin(), it)); 586 | keyPoses.erase(it); 587 | 588 | updateCursorSpin(); 589 | update(); 590 | 591 | nbKeyPosesSpin->setValue(static_cast(keyPoses.size())); 592 | emit keyPoseDeleted(id); // EXTERNAL SIGNAL 593 | qDebug() << "\033[35mkeyPoseDeleted(" << id << ")\033[0m"; 594 | 595 | onSetCursorToNextKeyPose(); 596 | } 597 | } 598 | 599 | void QFrameSelector::onSetCursorToStart() 600 | { 601 | onChangeCursor(start); 602 | } 603 | 604 | void QFrameSelector::onSetCursorToEnd() 605 | { 606 | onChangeCursor(end); 607 | } 608 | 609 | void QFrameSelector::onSetCursorToPreviousKeyPose() 610 | { 611 | auto it = keyPoses.rbegin(); 612 | while (it != keyPoses.rend() && *it >= cursor) 613 | it++; 614 | 615 | if (it != keyPoses.rend()) { 616 | onChangeCursor(*it); 617 | } 618 | } 619 | 620 | void QFrameSelector::onSetCursorToNextKeyPose() 621 | { 622 | auto it = keyPoses.begin(); 623 | while (it != keyPoses.end() && *it <= cursor) 624 | it++; 625 | 626 | if (it != keyPoses.end()) { 627 | 628 | onChangeCursor(*it); 629 | } 630 | } 631 | 632 | void QFrameSelector::onChangeStartSpin() 633 | { 634 | onChangeStart(startSpin->value()); 635 | } 636 | 637 | void QFrameSelector::onChangeEndSpin() 638 | { 639 | onChangeEnd(endSpin->value()); 640 | } 641 | 642 | void QFrameSelector::onChangeCursorSpin() 643 | { 644 | onChangeCursor(cursorSpin->value()); 645 | } 646 | 647 | void QFrameSelector::onChangeDurationSpin() 648 | { 649 | onChangeDuration(durationSpin->value()); 650 | } 651 | 652 | // -------------------------- PRIVATE FUNCTIONS ------------------------------- 653 | void QFrameSelector::updateCursorSpin() 654 | { 655 | if (keyPoses.find(cursor) != keyPoses.end()) { 656 | cursorSpin->setStyleSheet("background-color: yellow"); 657 | removeKeyPoseButton->setEnabled(true); 658 | } else { 659 | cursorSpin->setStyleSheet("background-color: #5555ff"); 660 | removeKeyPoseButton->setEnabled(false); 661 | } 662 | cursorSpin->setValue(cursor); 663 | } 664 | 665 | void QFrameSelector::updateStartSpin() 666 | { 667 | startSpin->setValue(start); 668 | } 669 | 670 | void QFrameSelector::updateEndSpin() 671 | { 672 | endSpin->setValue(end); 673 | } 674 | 675 | void QFrameSelector::updateDurationSpin() 676 | { 677 | durationSpin->setValue(*duration); 678 | } 679 | 680 | void QFrameSelector::moveKeyPoses(double gap, size_t iFirst) 681 | { 682 | std::set clone; 683 | size_t i = 0; 684 | double first { 0 }; 685 | for (double d : keyPoses) { 686 | if (i < iFirst) 687 | clone.insert(d); 688 | else { 689 | if (i == iFirst) 690 | first = d; 691 | 692 | clone.insert(d + gap); 693 | } 694 | i++; 695 | } 696 | keyPoses = clone; 697 | 698 | double left = (gap > 0) ? (first) : (first + gap); 699 | 700 | // emit keyPosesMoved before emitting cursorChanged to render the truly pose on cursor 701 | emit keyPosesMoved(gap, iFirst); // EXTERNAL SIGNAL 702 | qDebug() << "\033[35mkeyPosesMoved(" << gap << ", " << iFirst << ")\033[0m"; 703 | 704 | if (start >= left) { 705 | // start += gap; 706 | start = qMax(qMin(start + gap, *duration), 0.0); 707 | updateStartSpin(); 708 | 709 | emit startChanged(start); 710 | qDebug() << "\033[35mstartChanged(" << start << ")\033[0m"; 711 | } 712 | 713 | if (end >= left) { 714 | // end += gap; 715 | end = qMax(qMin(end + gap, *duration), 0.0); 716 | updateEndSpin(); 717 | 718 | emit endChanged(end); 719 | qDebug() << "\033[35mendChanged(" << end << ")\033[0m"; 720 | } 721 | 722 | if (cursor >= left) { 723 | bool cursorOnKeyPose = qAbs(cursor - first) < 1e-5; 724 | 725 | cursor = qMax(cursor + gap, 0.0); 726 | updateCursorSpin(); 727 | 728 | if (!cursorOnKeyPose) { 729 | emit cursorChanged(cursor); 730 | qDebug() << "\033[35mcursorChanged(" << cursor << ")\033[0m"; 731 | } 732 | } 733 | 734 | update(); 735 | } 736 | 737 | void QFrameSelector::deleteZone(double time, double time2) 738 | { 739 | double left = qMin(time, time2); 740 | double right = qMax(time, time2); 741 | 742 | double dist = right - left; 743 | 744 | auto it = keyPoses.begin(); 745 | size_t id = 0; 746 | bool first = true; 747 | while (it != keyPoses.end()) { 748 | double keyPose = *it; 749 | 750 | if (keyPose >= left) { 751 | keyPoses.erase(it++); 752 | 753 | if (keyPose > right) { 754 | if (first) { 755 | emit keyPosesMoved(-dist, id); 756 | qDebug() << "\033[35mkeyPosesMoved(" << -dist << ", " << id << ")\033[0m"; 757 | first = false; 758 | } 759 | keyPoses.insert(keyPose - dist); 760 | } else { 761 | emit keyPoseDeleted(id); 762 | qDebug() << "\033[35mkeyPoseDeleted(" << id << ")\033[0m"; 763 | } 764 | } else { 765 | ++it; 766 | ++id; 767 | } 768 | } 769 | nbKeyPosesSpin->setValue(static_cast(keyPoses.size())); 770 | 771 | double newStart = qMax(qMax(qMin(start, left), start - dist), 0.0); 772 | if (qAbs(newStart - start) > 1e-5) { 773 | start = newStart; 774 | updateStartSpin(); 775 | 776 | emit startChanged(start); 777 | qDebug() << "\033[35mstartChanged(" << start << ")\033[0m"; 778 | } 779 | 780 | double newEnd = qMax(qMax(qMin(end, left), end - dist), 0.0); 781 | if (qAbs(newEnd - end) > 1e-5) { 782 | end = newEnd; 783 | updateEndSpin(); 784 | 785 | emit endChanged(end); 786 | qDebug() << "\033[35mendChanged(" << end << ")\033[0m"; 787 | } 788 | 789 | update(); 790 | } 791 | 792 | void QFrameSelector::setSplitter(QSplitter* splitter) 793 | { 794 | m_splitter = splitter; 795 | } 796 | 797 | void QFrameSelector::setRightSpacer(QFrame* value) 798 | { 799 | rightSpacer = value; 800 | } 801 | 802 | void QFrameSelector::redrawPlayZone() 803 | { 804 | QList sizes = m_splitter->sizes(); 805 | sizes[0] = *zero + start * *pixPerSec - 3; 806 | sizes[1] = (end - start) * *pixPerSec - 3; 807 | sizes[2] = width() - sizes[0] - sizes[1] - 3 - 3 - 3 - 4; 808 | // sizes[2] = 0; 809 | m_splitter->setSizes(sizes); 810 | // m_splitter->setSizes({100, 100}); 811 | // leftSpacer->resize(*zero + start * *pixPerSec, h); 812 | // leftSpacer->setMinimumWidth(static_cast(*zero + start * *pixPerSec - leftSlider->width())); 813 | 814 | // leftSpacer->setMinimumWidth(static_cast(*zero + start * *pixPerSec)); 815 | // playZone->setMinimumWidth(static_cast((end - start) * *pixPerSec)); 816 | } 817 | 818 | // -------------------------- GETTERS ----------------------------------------- 819 | double QFrameSelector::getStart() const 820 | { 821 | return start; 822 | } 823 | 824 | double* QFrameSelector::getStart() 825 | { 826 | return &start; 827 | } 828 | 829 | double* QFrameSelector::getEnd() 830 | { 831 | return &end; 832 | } 833 | 834 | double* QFrameSelector::getCursor() 835 | { 836 | return &cursor; 837 | } 838 | 839 | double QFrameSelector::getEnd() const 840 | { 841 | return end; 842 | } 843 | 844 | double QFrameSelector::getCursor() const 845 | { 846 | return cursor; 847 | } 848 | 849 | int QFrameSelector::getNbKeyPoses() const 850 | { 851 | return static_cast(keyPoses.size()); 852 | } 853 | 854 | double QFrameSelector::getKeyPose(int id) const 855 | { 856 | auto it = keyPoses.begin(); 857 | while (it != keyPoses.end() && id-- > 0) 858 | it++; 859 | 860 | return *it; 861 | } 862 | 863 | std::set QFrameSelector::getKeyPoses() const 864 | { 865 | return keyPoses; 866 | } 867 | 868 | std::set* QFrameSelector::getKeyPoses() 869 | { 870 | return &keyPoses; 871 | } 872 | 873 | // -------------------------- SETTERS ----------------------------------------- 874 | void QFrameSelector::setCursor(double time) 875 | { 876 | cursor = time; 877 | } 878 | 879 | void QFrameSelector::setKeyPoses(const std::set& value) 880 | { 881 | keyPoses = value; 882 | } 883 | 884 | void QFrameSelector::setShiftDown(bool* value) 885 | { 886 | shiftDown = value; 887 | } 888 | 889 | void QFrameSelector::setStart(double value) 890 | { 891 | start = value; 892 | } 893 | 894 | void QFrameSelector::setEnd(double value) 895 | { 896 | end = value; 897 | } 898 | 899 | void QFrameSelector::setDuration(double time) 900 | { 901 | *duration = time; 902 | } 903 | 904 | // 905 | // -------------------------- REFERENCES SETTERS ------------------------------ 906 | void QFrameSelector::setLeftSpacer(QFrame* value) 907 | { 908 | leftSpacer = value; 909 | } 910 | 911 | //void QFrameSelector::setLeftSlider(QWidget* value) 912 | //{ 913 | // leftSlider = value; 914 | //} 915 | 916 | void QFrameSelector::setPlayZone(QFrame* value) 917 | { 918 | playZone = value; 919 | } 920 | 921 | //void QFrameSelector::setRightSlider(QWidget* value) 922 | //{ 923 | // rightSlider = value; 924 | //} 925 | // 926 | 927 | void QFrameSelector::setCursorSpin(QDoubleSpinBox* value) 928 | { 929 | cursorSpin = value; 930 | } 931 | 932 | void QFrameSelector::setStartSpin(QDoubleSpinBox* value) 933 | { 934 | startSpin = value; 935 | } 936 | 937 | void QFrameSelector::setEndSpin(QDoubleSpinBox* value) 938 | { 939 | endSpin = value; 940 | } 941 | 942 | void QFrameSelector::setDurationSpin(QDoubleSpinBox* value) 943 | { 944 | durationSpin = value; 945 | } 946 | 947 | void QFrameSelector::setRemoveKeyPoseButton(QToolButton* value) 948 | { 949 | removeKeyPoseButton = value; 950 | } 951 | 952 | void QFrameSelector::setStartInc(QDoubleSpinBox* value) 953 | { 954 | startInc = value; 955 | } 956 | 957 | void QFrameSelector::setEndInc(QDoubleSpinBox* value) 958 | { 959 | endInc = value; 960 | } 961 | 962 | void QFrameSelector::setNbKeyPosesSpin(QSpinBox* value) 963 | { 964 | nbKeyPosesSpin = value; 965 | } 966 | void QFrameSelector::setCtrlDown(bool* value) 967 | { 968 | ctrlDown = value; 969 | } 970 | 971 | void QFrameSelector::setMidMouseDown(bool* value) 972 | { 973 | midMouseDown = value; 974 | } 975 | -------------------------------------------------------------------------------- /src/AnimTimeline/qframeselector.h: -------------------------------------------------------------------------------- 1 | #ifndef QFRAMESELECTOR_H 2 | #define QFRAMESELECTOR_H 3 | 4 | //#include 5 | #include "configurations.h" 6 | //#include 7 | #include "qwidgetruler.h" 8 | 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | 16 | class QFrameSelector : public QFrame { 17 | Q_OBJECT 18 | public: 19 | explicit QFrameSelector(QWidget* parent = nullptr); 20 | ~QFrameSelector() override; 21 | 22 | // void updatePlayZone(); 23 | 24 | double nearestStep(double time) const; 25 | 26 | protected: 27 | virtual void paintEvent(QPaintEvent* event) override; 28 | // virtual void resizeEvent(QResizeEvent * event) override; 29 | 30 | void mousePressEvent(QMouseEvent* event) override; 31 | void mouseMoveEvent(QMouseEvent* event) override; 32 | void mouseReleaseEvent(QMouseEvent* event) override; 33 | 34 | signals: 35 | void cursorChanged(double time); // EXTERNAL SIGNAL 36 | void startChanged(double time); // EXTERNAL SIGNAL 37 | void endChanged(double time); // EXTERNAL SIGNAL 38 | void durationChanged(double time); // EXTERNAL SIGNAL 39 | 40 | void keyPoseAdded(double time); // EXTERNAL SIGNAL 41 | void keyPoseDeleted(size_t id); // EXTERNAL SIGNAL 42 | void keyPoseChanged(size_t id); // EXTERNAL SIGNAL 43 | void keyPosesMoved(double gap, size_t first); // EXTERNAL SIGNAL 44 | void keyPoseMoved(size_t id, double time); // EXTERNAL SIGNAL 45 | 46 | public slots: 47 | // ---------------------- EXTERNAL SLOTS ---------------------------------- 48 | void onAddingKeyPose(double time = -1.0, bool internal = true); // EXTERNAL SLOT 49 | void onClearKeyPoses(); // EXTERNAL SLOT 50 | 51 | void onChangeStart(double time, bool internal = true); // EXTERNAL SLOT 52 | void onChangeEnd(double time, bool internal = true); // EXTERNAL SLOT 53 | void onChangeCursor(double time, bool internal = true); // EXTERNAL SLOT 54 | void onChangeDuration(double time, bool internal = true); // EXTERNAL SLOT 55 | 56 | void prepareBackground(int width, int height); 57 | 58 | void onRulerChange(); 59 | // 60 | // ---------------------- INTERNAL SLOTS ---------------------------------- 61 | void onSlideLeftSlider(int deltaX); 62 | void onSlideRightSlider(int deltaX); 63 | // void onLeftSlideRelease(); 64 | // void onRightSlideRelease(); 65 | void onSplitterMove(int pos, int index); 66 | 67 | void onDeleteKeyPose(); 68 | 69 | void onSetCursorToStart(); 70 | void onSetCursorToEnd(); 71 | void onSetCursorToPreviousKeyPose(); 72 | void onSetCursorToNextKeyPose(); 73 | 74 | void onChangeStartSpin(); 75 | void onChangeEndSpin(); 76 | void onChangeCursorSpin(); 77 | void onChangeDurationSpin(); 78 | 79 | void updateCursorSpin(); 80 | void updateStartSpin(); 81 | void updateEndSpin(); 82 | void updateDurationSpin(); 83 | void redrawPlayZone(); 84 | 85 | private: 86 | // ---------------------- PRIVATE FUNCTIONS -------------------------------- 87 | void moveKeyPoses(double gap, size_t first = 0); 88 | void deleteZone(double time, double time2); 89 | 90 | private: 91 | // int paintCounter { 0 }; 92 | // uint rulerChangeCounter = 0; 93 | 94 | double start; 95 | double end; 96 | double cursor; 97 | 98 | int* nbInterval; 99 | double* step; 100 | double* pixPerSec; 101 | double* zero; 102 | double* duration; 103 | 104 | bool m_rulerChanged = false; 105 | QPixmap * m_pixmapBackground = nullptr; 106 | // question : why QSet is unordered 107 | // QSet keyPoses; 108 | std::set keyPoses; 109 | 110 | // bool sliding { false }; 111 | bool mouseLeftClicked { false }; 112 | 113 | bool* midMouseDown; 114 | 115 | bool* shiftDown; 116 | bool* ctrlDown; 117 | 118 | int updateKeyPoseFlash { 0 }; 119 | double keyPoseFlash; 120 | 121 | QTimer* timer; 122 | 123 | // ---------------------- REFERENCES -------------------------------------- 124 | QWidgetRuler* widgetRuler; 125 | 126 | QFrame* leftSpacer; 127 | QFrame* rightSpacer; 128 | // QWidget* leftSlider; 129 | QFrame* playZone; 130 | // QWidget* rightSlider; 131 | QSplitter * m_splitter; 132 | 133 | QDoubleSpinBox* cursorSpin; 134 | QDoubleSpinBox* startSpin; 135 | QDoubleSpinBox* endSpin; 136 | QDoubleSpinBox* durationSpin; 137 | 138 | QToolButton* removeKeyPoseButton; 139 | QDoubleSpinBox* startInc; 140 | QDoubleSpinBox* endInc; 141 | QSpinBox* nbKeyPosesSpin; 142 | 143 | public: 144 | // --------------------------- GETTERS ------------------------------------ 145 | double getStart() const; 146 | double* getStart(); 147 | double* getEnd(); 148 | double* getCursor(); 149 | double getEnd() const; 150 | double getCursor() const; 151 | int getNbKeyPoses() const; 152 | double getKeyPose(int id) const; 153 | std::set getKeyPoses() const; 154 | std::set* getKeyPoses(); 155 | 156 | // --------------------------- SETTERS ------------------------------------ 157 | void setCursor(double time); 158 | void setKeyPoses(const std::set& value); 159 | void setShiftDown(bool* value); 160 | void setStart(double value); 161 | void setEnd(double value); 162 | void setDuration(double time); 163 | 164 | // 165 | // ---------------------- REFERENCES SETTERS ------------------------------ 166 | void setLeftSpacer(QFrame* value); 167 | // void setLeftSlider(QWidget* value); 168 | void setPlayZone(QFrame* value); 169 | // void setRightSlider(QWidget *value); 170 | 171 | void setCursorSpin(QDoubleSpinBox* value); 172 | void setStartSpin(QDoubleSpinBox* value); 173 | void setEndSpin(QDoubleSpinBox* value); 174 | void setDurationSpin(QDoubleSpinBox* value); 175 | 176 | void setRemoveKeyPoseButton(QToolButton* value); 177 | void setStartInc(QDoubleSpinBox* value); 178 | void setEndInc(QDoubleSpinBox* value); 179 | void setNbKeyPosesSpin(QSpinBox* value); 180 | void setMidMouseDown(bool* value); 181 | void setCtrlDown(bool* value); 182 | void setRightSpacer(QFrame *value); 183 | void setSplitter(QSplitter *splitter); 184 | }; 185 | 186 | #endif // QFRAMESELECTOR_H 187 | -------------------------------------------------------------------------------- /src/AnimTimeline/qframetimescale.cpp: -------------------------------------------------------------------------------- 1 | //#include 2 | #include "qframetimescale.h" 3 | //#include 4 | #include "qwidgetruler.h" 5 | 6 | #include 7 | #include 8 | 9 | QFrameTimescale::QFrameTimescale(QWidget* parent) 10 | : QFrame(parent) 11 | { 12 | widgetRuler = static_cast(parent); 13 | 14 | nbInterval = widgetRuler->getNbInterval(); 15 | step = widgetRuler->getStep(); 16 | pixPerSec = widgetRuler->getPixPerSec(); 17 | 18 | drawLock = widgetRuler->getTimescaleLock(); 19 | } 20 | 21 | void QFrameTimescale::paintEvent(QPaintEvent*) 22 | { 23 | if (m_rulerChanged) { 24 | int w = width(); 25 | int h = height(); 26 | 27 | if (m_pixmapBackground != nullptr) 28 | delete m_pixmapBackground; 29 | m_pixmapBackground = new QPixmap(this->size()); 30 | m_pixmapBackground->fill(QColor(255, 255, 255, 0)); 31 | // m_pixmapBackground->fill(QColor(255, 0, 0, 255)); 32 | 33 | QPainter painter(m_pixmapBackground); 34 | // int h = height; 35 | painter.setRenderHint(QPainter::HighQualityAntialiasing); 36 | 37 | painter.drawText(0, 11, "sec"); 38 | for (int i = 1; i < *nbInterval; i++) { 39 | int x = static_cast(*pixPerSec * *step * i); 40 | QString time = QString::number((i - 1) * *step); 41 | int dec = time.size() * 6 / 2; 42 | painter.drawText(x - dec, 11, time); 43 | } 44 | 45 | m_rulerChanged = false; 46 | } 47 | 48 | QPainter painter(this); 49 | painter.drawPixmap(rect(), *m_pixmapBackground); 50 | } 51 | 52 | //void QFrameTimescale::resizeEvent(QResizeEvent *event) 53 | //{ 54 | //// qDebug() << "QFrameTimescale::resizeEvent " << ++counter; 55 | 56 | //// QSize size = event->size(); 57 | 58 | //} 59 | 60 | void QFrameTimescale::onRulerChange() 61 | { 62 | m_rulerChanged = true; 63 | } 64 | 65 | void QFrameTimescale::setDrawLock(bool* value) 66 | { 67 | drawLock = value; 68 | } 69 | -------------------------------------------------------------------------------- /src/AnimTimeline/qframetimescale.h: -------------------------------------------------------------------------------- 1 | #ifndef QFRAMETIMESCALE_H 2 | #define QFRAMETIMESCALE_H 3 | 4 | //#include 5 | #include "qwidgetruler.h" 6 | 7 | #include 8 | #include 9 | 10 | class QFrameTimescale : public QFrame { 11 | Q_OBJECT 12 | public: 13 | explicit QFrameTimescale(QWidget* parent = nullptr); 14 | 15 | void setDrawLock(bool* value); 16 | 17 | signals: 18 | 19 | protected: 20 | virtual void paintEvent(QPaintEvent* event) override; 21 | // virtual void resizeEvent(QResizeEvent * event) override; 22 | 23 | public slots: 24 | void onRulerChange(); 25 | 26 | private: 27 | QWidgetRuler* widgetRuler; 28 | 29 | QPixmap * m_pixmapBackground = nullptr; 30 | 31 | bool m_rulerChanged = false; 32 | 33 | int* nbInterval; 34 | double* step; 35 | double* pixPerSec; 36 | 37 | bool* drawLock; 38 | // int counter { 0 }; 39 | 40 | int align; 41 | }; 42 | 43 | #endif // QFRAMETIMESCALE_H 44 | -------------------------------------------------------------------------------- /src/AnimTimeline/qscrollarearuler.cpp: -------------------------------------------------------------------------------- 1 | //#include 2 | #include "qscrollarearuler.h" 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | QScrollAreaRuler::QScrollAreaRuler(QWidget* parent) 10 | : QScrollArea(parent) 11 | { 12 | 13 | horizontalScrollBar()->setStyleSheet("\ 14 | QScrollBar:horizontal {\ 15 | background: transparent;\ 16 | }\ 17 | \ 18 | QScrollBar::handle:horizontal {\ 19 | background: white;\ 20 | }\ 21 | \ 22 | QScrollBar::add-line:horizontal {\ 23 | border: none;\ 24 | background: transparent;\ 25 | }\ 26 | \ 27 | QScrollBar::sub-line:horizontal {\ 28 | border: none;\ 29 | background: transparent;\ 30 | }"); 31 | } 32 | 33 | void QScrollAreaRuler::keyPressEvent(QKeyEvent* event) 34 | { 35 | // qDebug() << "QScrollAreaRuler::keyPressEvent event : " << event; 36 | 37 | switch (event->key()) { 38 | 39 | case Qt::Key_Control: 40 | ctrlDown = true; 41 | break; 42 | 43 | case Qt::Key_Space: 44 | playPause->onChangeMode(); 45 | break; 46 | 47 | case Qt::Key_Delete: 48 | emit removeKeyPose(); 49 | break; 50 | 51 | case Qt::Key_I: 52 | if (shiftDown) { 53 | emit removeKeyPose(); 54 | } else { 55 | emit addKeyPose(); 56 | // TODO : add key pose on mouse if no key pose selected 57 | } 58 | break; 59 | 60 | case Qt::Key_X: 61 | emit removeKeyPose(); 62 | break; 63 | 64 | 65 | case Qt::Key_Shift: 66 | shiftDown = true; 67 | break; 68 | 69 | case Qt::Key_Left: 70 | emit previousKeyPose(); 71 | break; 72 | 73 | case Qt::Key_Right: 74 | emit nextKeyPose(); 75 | break; 76 | 77 | // case Qt::Key_Escape: 78 | // animTimeline->hide(); 79 | // break; 80 | 81 | case Qt::Key_Up: 82 | emit durationChanged(spinDuration->value() + spinDuration->singleStep()); 83 | break; 84 | 85 | case Qt::Key_Down: 86 | emit durationChanged(spinDuration->value() - spinDuration->singleStep()); 87 | break; 88 | 89 | case Qt::Key_Z: 90 | if (ctrlDown) { 91 | if (shiftDown) { 92 | emit redo(); 93 | } else { 94 | emit undo(); 95 | } 96 | } 97 | break; 98 | 99 | case Qt::Key_U: 100 | emit undo(); 101 | break; 102 | 103 | case Qt::Key_R: 104 | emit redo(); 105 | } 106 | } 107 | 108 | void QScrollAreaRuler::keyReleaseEvent(QKeyEvent* event) 109 | { 110 | // qDebug() << "QScrollAreaRuler::keyReleaseEvent event : " << event; 111 | 112 | switch (event->key()) { 113 | 114 | case Qt::Key_Control: 115 | ctrlDown = false; 116 | break; 117 | 118 | case Qt::Key_Shift: 119 | shiftDown = false; 120 | break; 121 | } 122 | } 123 | 124 | void QScrollAreaRuler::wheelEvent(QWheelEvent* event) 125 | { 126 | // qDebug() << "scroll area ruler width : " << width(); 127 | int ry = event->angleDelta().ry(); 128 | 129 | // change dialog width 130 | // if (shiftDown && ctrlDown) { 131 | // int curWidth = animTimeline->width(); 132 | // int minWidth = animTimeline->minimumWidth(); 133 | 134 | // if (curWidth == minWidth && ry <= 0) 135 | // return; 136 | 137 | // if (ry + curWidth <= minWidth) 138 | // ry = minWidth - curWidth; 139 | 140 | // int newX = animTimeline->x() - ry; 141 | // int newY = animTimeline->y() + 1; 142 | // int newWidth = animTimeline->width() + 1 + ry; 143 | // int newHeight = animTimeline->height(); 144 | 145 | // ruler->onDrawRuler(newWidth - 2); 146 | // animTimeline->setGeometry(newX, newY, newWidth, newHeight); 147 | 148 | // } 149 | // next/previous keyPose 150 | if (shiftDown) { 151 | if (ry > 0) { 152 | emit nextKeyPose(); 153 | } else { 154 | emit previousKeyPose(); 155 | } 156 | 157 | } 158 | // scroll left/right bar 159 | else if (ctrlDown) { 160 | horizontalScrollBar()->setValue(static_cast(horizontalScrollBar()->value() + ry * AnimTimeline::SLIDE_SPEED)); 161 | 162 | } 163 | // zoom in/out 164 | else { 165 | int newRulerWidth = static_cast(ruler->minimumWidth() + ry * AnimTimeline::ZOOM_SPEED * ruler->minimumWidth() / width()); 166 | if (newRulerWidth <= width() - 2) { 167 | if (ruler->minimumWidth() == width() - 2) { 168 | return; 169 | } else { 170 | newRulerWidth = width() - 2; 171 | } 172 | } 173 | // qDebug() << "new ruler width : " << newRulerWidth; 174 | 175 | double hScroll = horizontalScrollBar()->value(); 176 | double x = event->x(); 177 | 178 | double* zero = ruler->getZero(); 179 | double* pixPerSec = ruler->getPixPerSec(); 180 | 181 | double time = (hScroll + x - *zero) / *pixPerSec; 182 | time = selector->nearestStep(time); 183 | // qDebug() << "TIME = " << time; 184 | 185 | ruler->onDrawRuler(newRulerWidth); 186 | 187 | double a = time * *pixPerSec + *zero; 188 | 189 | double hScrollAfterProjection = a - x; 190 | 191 | // qDebug() << "scroll : " << hScrollAfterProjection; 192 | horizontalScrollBar()->setValue(static_cast(hScrollAfterProjection)); 193 | } 194 | event->accept(); // parent is animTimeline (root) with non event catching 195 | } 196 | 197 | void QScrollAreaRuler::mousePressEvent(QMouseEvent* event) 198 | { 199 | if (event->button() == Qt::MiddleButton) { 200 | setCursor(Qt::SplitHCursor); 201 | mousePosX = event->x(); 202 | sliderPos = horizontalScrollBar()->value(); 203 | 204 | midMouseDown = true; 205 | } 206 | } 207 | 208 | void QScrollAreaRuler::mouseReleaseEvent(QMouseEvent* event) 209 | { 210 | if (event->button() == Qt::MiddleButton) { 211 | midMouseDown = false; 212 | setCursor(Qt::ArrowCursor); 213 | } 214 | } 215 | 216 | void QScrollAreaRuler::mouseMoveEvent(QMouseEvent* event) 217 | { 218 | if (midMouseDown) { 219 | horizontalScrollBar()->setValue((sliderPos + mousePosX - event->x())); 220 | } 221 | } 222 | 223 | void QScrollAreaRuler::setAnimTimeline(FormAnimTimeline* value) 224 | { 225 | animTimeline = value; 226 | } 227 | 228 | void QScrollAreaRuler::setPlayPause(QToolButtonPlayPause* value) 229 | { 230 | playPause = value; 231 | } 232 | 233 | void QScrollAreaRuler::setRuler(QWidgetRuler* value) 234 | { 235 | ruler = value; 236 | } 237 | 238 | bool* QScrollAreaRuler::getShiftDown() 239 | { 240 | return &shiftDown; 241 | } 242 | 243 | void QScrollAreaRuler::onKeyPress(QKeyEvent* event) 244 | { 245 | switch (event->key()) { 246 | case Qt::Key_Right: 247 | case Qt::Key_Left: 248 | case Qt::Key_Up: 249 | case Qt::Key_Down: 250 | return; 251 | } 252 | keyPressEvent(event); 253 | } 254 | 255 | void QScrollAreaRuler::onKeyRelease(QKeyEvent* event) 256 | { 257 | keyReleaseEvent(event); 258 | } 259 | 260 | void QScrollAreaRuler::setCursorSpin(QDoubleSpinBoxSmart* value) 261 | { 262 | cursorSpin = value; 263 | } 264 | 265 | bool* QScrollAreaRuler::getMidMouseDown() 266 | { 267 | return &midMouseDown; 268 | } 269 | 270 | void QScrollAreaRuler::setSelector(QFrameSelector* value) 271 | { 272 | selector = value; 273 | } 274 | 275 | bool* QScrollAreaRuler::getCtrlDown() 276 | { 277 | return &ctrlDown; 278 | } 279 | 280 | void QScrollAreaRuler::setSpinDuration(QDoubleSpinBoxSmart* value) 281 | { 282 | spinDuration = value; 283 | } 284 | -------------------------------------------------------------------------------- /src/AnimTimeline/qscrollarearuler.h: -------------------------------------------------------------------------------- 1 | #ifndef QSCROLLAREARULER_H 2 | #define QSCROLLAREARULER_H 3 | 4 | //#include 5 | #include "FormAnimTimeline.h" 6 | 7 | //#include 8 | //#include "animtimeline.h" 9 | //#include 10 | #include "qdoublespinboxsmart.h" 11 | //#include 12 | #include "qframeselector.h" 13 | //#include 14 | #include "qwidgetruler.h" 15 | 16 | #include 17 | #include 18 | #include 19 | 20 | class QScrollAreaRuler : public QScrollArea { 21 | Q_OBJECT 22 | public: 23 | explicit QScrollAreaRuler(QWidget* parent = nullptr); 24 | 25 | bool* getShiftDown(); 26 | void setRuler(QWidgetRuler* value); 27 | void setPlayPause(QToolButtonPlayPause* value); 28 | void setAnimTimeline(FormAnimTimeline* value); 29 | void setSpinDuration(QDoubleSpinBoxSmart* value); 30 | bool* getCtrlDown(); 31 | void setSelector(QFrameSelector* value); 32 | bool* getMidMouseDown(); 33 | void setCursorSpin(QDoubleSpinBoxSmart* value); 34 | 35 | protected: 36 | void keyPressEvent(QKeyEvent* event) override; 37 | void keyReleaseEvent(QKeyEvent* event) override; 38 | 39 | void wheelEvent(QWheelEvent* event) override; 40 | 41 | void mousePressEvent(QMouseEvent* event) override; 42 | void mouseReleaseEvent(QMouseEvent* event) override; 43 | void mouseMoveEvent(QMouseEvent* event) override; 44 | 45 | signals: 46 | void keyPoseOnMouseAdded(); 47 | void removeKeyPose(); 48 | void previousKeyPose(); 49 | void nextKeyPose(); 50 | void durationChanged(double time); 51 | void addKeyPose(); 52 | 53 | void undo(); 54 | void redo(); 55 | 56 | public slots: 57 | void onKeyPress(QKeyEvent* event); 58 | void onKeyRelease(QKeyEvent* event); 59 | 60 | private: 61 | int mousePosX; 62 | int sliderPos; 63 | 64 | QWidgetRuler* ruler; 65 | QToolButtonPlayPause* playPause; 66 | FormAnimTimeline* animTimeline; 67 | QDoubleSpinBoxSmart* spinDuration; 68 | 69 | QDoubleSpinBoxSmart* cursorSpin; 70 | 71 | QFrameSelector* selector; 72 | 73 | bool ctrlDown = false; 74 | bool shiftDown = false; 75 | bool midMouseDown = false; 76 | bool align[5]; 77 | }; 78 | 79 | #endif // QSCROLLAREARULER_H 80 | -------------------------------------------------------------------------------- /src/AnimTimeline/qspinboxsmart.cpp: -------------------------------------------------------------------------------- 1 | //#include 2 | #include "qspinboxsmart.h" 3 | 4 | #include 5 | 6 | QSpinBoxSmart::QSpinBoxSmart(QWidget* parent) 7 | : QSpinBox(parent) 8 | { 9 | } 10 | 11 | void QSpinBoxSmart::wheelEvent(QWheelEvent* event) 12 | { 13 | 14 | int ry = (event->angleDelta().ry() > 0) ? (1) : (-1); 15 | if (ry > 0) { 16 | emit nextKeyPose(); 17 | } else { 18 | emit previousKeyPose(); 19 | } 20 | event->accept(); 21 | } 22 | 23 | void QSpinBoxSmart::keyPressEvent(QKeyEvent* event) 24 | { 25 | switch (event->key()) { 26 | case Qt::Key_Delete: 27 | emit deleteKeyPose(); 28 | break; 29 | 30 | default: 31 | event->ignore(); 32 | return; 33 | } 34 | 35 | event->accept(); 36 | } 37 | -------------------------------------------------------------------------------- /src/AnimTimeline/qspinboxsmart.h: -------------------------------------------------------------------------------- 1 | #ifndef QSPINBOXSMART_H 2 | #define QSPINBOXSMART_H 3 | 4 | #include 5 | #include 6 | #include 7 | 8 | class QSpinBoxSmart : public QSpinBox { 9 | Q_OBJECT 10 | public: 11 | explicit QSpinBoxSmart(QWidget* parent = nullptr); 12 | 13 | protected: 14 | void wheelEvent(QWheelEvent* event) override; 15 | void keyPressEvent(QKeyEvent* event) override; 16 | 17 | signals: 18 | void nextKeyPose(); 19 | void previousKeyPose(); 20 | void deleteKeyPose(); 21 | }; 22 | 23 | #endif // QSPINBOXSMART_H 24 | -------------------------------------------------------------------------------- /src/AnimTimeline/qtoolbuttonplaypause.cpp: -------------------------------------------------------------------------------- 1 | //#include 2 | #include "qtoolbuttonplaypause.h" 3 | 4 | #include 5 | #include 6 | 7 | QToolButtonPlayPause::QToolButtonPlayPause(QWidget* parent) 8 | : QToolButton(parent) 9 | { 10 | 11 | playIcon = new QIcon(); 12 | playIcon->addPixmap(QPixmap(":/images/play.png")); 13 | pauseIcon = new QIcon(); 14 | pauseIcon->addPixmap(QPixmap(":/images/pause.png")); 15 | 16 | this->setIcon(*playIcon); 17 | } 18 | 19 | QToolButtonPlayPause::~QToolButtonPlayPause() 20 | { 21 | delete playIcon; 22 | delete pauseIcon; 23 | } 24 | 25 | void QToolButtonPlayPause::mousePressEvent(QMouseEvent* event) 26 | { 27 | if (event->button() == Qt::LeftButton) { 28 | onChangeMode(); 29 | event->accept(); 30 | } 31 | } 32 | 33 | // EXTERNAL SLOT 34 | void QToolButtonPlayPause::onPlayMode() 35 | { 36 | if (play) { 37 | qDebug() << "\033[31mQToolButtonPlayPause::onPlayMode() : already on play mode\033[0m"; 38 | return; 39 | } 40 | 41 | this->setIcon(*pauseIcon); 42 | play = true; 43 | } 44 | 45 | // EXTERNAL SLOT 46 | void QToolButtonPlayPause::onPauseMode() 47 | { 48 | if (!play) { 49 | qDebug() << "\033[31mQToolButtonPlayPause::onPauseMode() : already on pause mode\033[0m"; 50 | return; 51 | } 52 | 53 | this->setIcon(*playIcon); 54 | play = false; 55 | } 56 | 57 | void QToolButtonPlayPause::onChangeMode() 58 | { 59 | if (play) { 60 | onPauseMode(); 61 | emit pauseClicked(); 62 | qDebug() << "\033[35mpauseClicked()\033[0m"; 63 | } else { 64 | onPlayMode(); 65 | emit playClicked(); 66 | qDebug() << "\033[35mplayClicked()\033[0m"; 67 | } 68 | } 69 | 70 | bool* QToolButtonPlayPause::getPlay() 71 | { 72 | return &play; 73 | } 74 | -------------------------------------------------------------------------------- /src/AnimTimeline/qtoolbuttonplaypause.h: -------------------------------------------------------------------------------- 1 | #ifndef QTOOLBUTTONPLAYPAUSE_H 2 | #define QTOOLBUTTONPLAYPAUSE_H 3 | 4 | #include 5 | #include 6 | 7 | class QToolButtonPlayPause : public QToolButton { 8 | Q_OBJECT 9 | public: 10 | explicit QToolButtonPlayPause(QWidget* parent = nullptr); 11 | ~QToolButtonPlayPause() override; 12 | 13 | bool* getPlay(); 14 | 15 | protected: 16 | void mousePressEvent(QMouseEvent* event) override; 17 | 18 | signals: 19 | void playClicked(); // EXTERNAL SIGNAL 20 | void pauseClicked(); // EXTERNAL SIGNAL 21 | 22 | public slots: 23 | void onPlayMode(); // EXTERNAL SLOT 24 | void onPauseMode(); // EXTERNAL SLOT 25 | 26 | void onChangeMode(); 27 | 28 | private: 29 | QIcon* playIcon; 30 | QIcon* pauseIcon; 31 | 32 | bool play = false; 33 | }; 34 | 35 | #endif // QTOOLBUTTONPLAYPAUSE_H 36 | -------------------------------------------------------------------------------- /src/AnimTimeline/qwidgetruler.cpp: -------------------------------------------------------------------------------- 1 | //#include 2 | #include "qwidgetruler.h" 3 | 4 | //#include 5 | #include "configurations.h" 6 | 7 | #include 8 | #include 9 | #include 10 | #include 11 | 12 | QWidgetRuler::QWidgetRuler(QWidget* parent) 13 | : QWidget(parent) 14 | { 15 | } 16 | 17 | int QWidgetRuler::drawRuler(int width) 18 | { 19 | int iStep = 0; 20 | while (iStep < nbSteps && width * steps[iStep] < 50 * maxDuration) 21 | iStep++; 22 | 23 | if (iStep == nbSteps) { 24 | qDebug() << "\033[31mQWidgetRuler::drawRuler : " << width << " too short step\033[0m"; 25 | 26 | return this->width(); 27 | } 28 | 29 | step = steps[iStep]; 30 | spinStart->setSingleStep(0.5 * step); 31 | spinEnd->setSingleStep(0.5 * step); 32 | spinCursor->setSingleStep(0.5 * step); 33 | spinDuration->setSingleStep(0.5 * step); 34 | 35 | nbInterval = qCeil(maxDuration / step) + 2; 36 | pixPerSec = (width / double(nbInterval)) / step; 37 | 38 | zero = pixPerSec * step; 39 | 40 | emit rulerChanged(); 41 | 42 | setMinimumWidth(width); 43 | 44 | 45 | update(); 46 | 47 | return width; 48 | } 49 | 50 | void QWidgetRuler::onDrawRuler(int width) 51 | { 52 | drawRuler(width); 53 | } 54 | 55 | void QWidgetRuler::setCtrlDown(bool* value) 56 | { 57 | ctrlDown = value; 58 | } 59 | 60 | void QWidgetRuler::setShiftDown(bool* value) 61 | { 62 | shiftDown = value; 63 | } 64 | 65 | void QWidgetRuler::setSpinDuration(QDoubleSpinBoxSmart* value) 66 | { 67 | spinDuration = value; 68 | } 69 | 70 | void QWidgetRuler::setSpinCursor(QDoubleSpinBoxSmart* value) 71 | { 72 | spinCursor = value; 73 | } 74 | 75 | void QWidgetRuler::setSpinEnd(QDoubleSpinBoxSmart* value) 76 | { 77 | spinEnd = value; 78 | } 79 | 80 | void QWidgetRuler::setSpinStart(QDoubleSpinBoxSmart* value) 81 | { 82 | spinStart = value; 83 | } 84 | 85 | bool* QWidgetRuler::getSelectorLock() 86 | { 87 | return &selectorLock; 88 | } 89 | 90 | bool* QWidgetRuler::getTimescaleLock() 91 | { 92 | return ×caleLock; 93 | } 94 | 95 | double* QWidgetRuler::getMaxDuration() 96 | { 97 | return &maxDuration; 98 | } 99 | 100 | double* QWidgetRuler::getZero() 101 | { 102 | return &zero; 103 | } 104 | 105 | double* QWidgetRuler::getPixPerSec() 106 | { 107 | return &pixPerSec; 108 | } 109 | 110 | int* QWidgetRuler::getNbInterval() 111 | { 112 | return &nbInterval; 113 | } 114 | 115 | double* QWidgetRuler::getStep() 116 | { 117 | return &step; 118 | } 119 | -------------------------------------------------------------------------------- /src/AnimTimeline/qwidgetruler.h: -------------------------------------------------------------------------------- 1 | #ifndef QWIDGETRULER_H 2 | #define QWIDGETRULER_H 3 | 4 | //#include 5 | #include "configurations.h" 6 | //#include 7 | #include "qdoublespinboxsmart.h" 8 | 9 | #include 10 | #include 11 | #include 12 | 13 | class QWidgetRuler : public QWidget { 14 | Q_OBJECT 15 | public: 16 | explicit QWidgetRuler(QWidget* parent = nullptr); 17 | 18 | double* getStep(); 19 | int* getNbInterval(); 20 | double* getPixPerSec(); 21 | int drawRuler(int newWidth); 22 | double* getZero(); 23 | double* getMaxDuration(); 24 | bool* getTimescaleLock(); 25 | bool* getSelectorLock(); 26 | void setSpinStart(QDoubleSpinBoxSmart* value); 27 | void setSpinEnd(QDoubleSpinBoxSmart* value); 28 | void setSpinCursor(QDoubleSpinBoxSmart* value); 29 | void setSpinDuration(QDoubleSpinBoxSmart* value); 30 | 31 | void setShiftDown(bool* value); 32 | 33 | void setCtrlDown(bool* value); 34 | 35 | signals: 36 | void rulerZoomed(QWheelEvent* event, double xr); 37 | void rulerChanged(); 38 | 39 | public slots: 40 | void onDrawRuler(int width); 41 | 42 | private: 43 | static const int nbSteps = 11; 44 | const double steps[nbSteps] = { 0.05, 0.1, 0.2, 0.5, 1.0, 2.0, 5.0, 10.0, 20.0, 50.0, 100.0 }; 45 | 46 | bool* ctrlDown; 47 | bool* shiftDown; 48 | 49 | double step; 50 | double pixPerSec; 51 | double zero; 52 | double maxDuration; 53 | 54 | QDoubleSpinBoxSmart* spinStart; 55 | QDoubleSpinBoxSmart* spinEnd; 56 | QDoubleSpinBoxSmart* spinCursor; 57 | QDoubleSpinBoxSmart* spinDuration; 58 | 59 | int nbInterval { 0 }; 60 | bool timescaleLock { true }; 61 | bool selectorLock { true }; 62 | 63 | bool align[2]; 64 | }; 65 | 66 | #endif // QWIDGETRULER_H 67 | -------------------------------------------------------------------------------- /src/AnimTimeline/timeline.qrc: -------------------------------------------------------------------------------- 1 | 2 | 3 | images/leftSlider.png 4 | images/rightSlider.png 5 | images/key.png 6 | images/end.png 7 | images/forward.png 8 | images/pause.png 9 | images/play.png 10 | images/rearward.png 11 | images/start.png 12 | images/plus.png 13 | images/less.png 14 | images/deleteKey.png 15 | images/help.png 16 | 17 | 18 | -------------------------------------------------------------------------------- /src/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | CMAKE_MINIMUM_REQUIRED( VERSION 3.8 ) 2 | PROJECT(AnimTimeline) 3 | # 4 | # ################################################################################ 5 | # # Compiler and linker options 6 | 7 | # SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11") 8 | set(CMAKE_INCLUDE_CURRENT_DIR ON) 9 | # 10 | # ################################################################################ 11 | # # Sources and headers 12 | # FIND_PACKAGE(Qt5 COMPONENTS Core Widgets REQUIRED) 13 | find_package(Qt5 COMPONENTS Core Widgets REQUIRED) 14 | # 15 | FILE(GLOB_RECURSE headers *.h) 16 | FILE(GLOB_RECURSE sources *.cpp) 17 | # 18 | file(GLOB_RECURSE forms *.ui) 19 | file(GLOB resources AnimTimeline/timeline.qrc) 20 | # 21 | # #add_definitions(${Qt5Core_DEFINITIONS}) 22 | # #add_definitions(${Qt5Widges_DEFINITIONS}) 23 | SET(CMAKE_AUTOMOC ON) 24 | SET(CMAKE_AUTORCC ON) 25 | SET(CMAKE_AUTOUIC ON) 26 | 27 | # qt5_wrap_ui(app_uis_moc ${forms}) 28 | 29 | # 30 | # #INCLUDE_DIRECTORIES(${CMAKE_CURRENT_BINARY_DIR} ${CMAKE_CURRENT_SOURCE_DIR} 31 | # include_directories( 32 | # . 33 | # src/ 34 | # AnimTimeline/ #for ui include "ui_animtimeline.h", moc not visible 35 | # ${CMAKE_CURRENT_BINARY_DIR} 36 | # # ${CMAKE_CURRENT_SOURCE_DIR} 37 | # ) 38 | # 39 | add_library(${PROJECT_NAME} SHARED 40 | ${sources} 41 | ${forms} 42 | ${headers} 43 | ${resources} 44 | ) 45 | # #add_definitions( ${Qt5Core_DEFINITIONS} ) 46 | # #add_definitions( ${Qt5Widges_DEFINITIONS} ) 47 | # 48 | # ################################################################################ 49 | # # Compile target 50 | # #ADD_EXECUTABLE(${PROJECT_NAME} ${V1_SOURCE_FILES} ${V1_HEADER_FILES} ${CMAKE_CURRENT_SOURCE_DIR}/resource/timeline.qrc) 51 | # ADD_EXECUTABLE(${PROJECT_NAME} ${sources} ${headers} ${app_uis} src/AnimTimeline/timeline.qrc) 52 | # # https://www.kdab.com/using-cmake-with-qt-5/ 53 | # qt5_use_modules(${PROJECT_NAME} Core Widgets) 54 | # 55 | target_link_libraries(${PROJECT_NAME} ${M_Qt5_LIBRARIES}) 56 | 57 | add_definitions(-DQT_NO_DEBUG_OUTPUT) 58 | # if(CMAKE_BUILD_TYPE MATCHES "Release") 59 | # add_definitions(-DQT_NO_DEBUG_OUTPUT) 60 | # endif() 61 | -------------------------------------------------------------------------------- /testApplication.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hiergaut/AnimTimeline/1998ba097628106607888c4f0871173fe6f281a1/testApplication.png -------------------------------------------------------------------------------- /timeline.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hiergaut/AnimTimeline/1998ba097628106607888c4f0871173fe6f281a1/timeline.png --------------------------------------------------------------------------------