1 /* 2 * Copyright (C) 2018-2021 Alexandros Theodotou <alex at zrythm dot org> 3 * 4 * This file is part of Zrythm 5 * 6 * Zrythm is free software: you can redistribute it and/or modify 7 * it under the terms of the GNU Affero General Public License as published by 8 * the Free Software Foundation, either version 3 of the License, or 9 * (at your option) any later version. 10 * 11 * Zrythm is distributed in the hope that it will be useful, 12 * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 * GNU Affero General Public License for more details. 15 * 16 * You should have received a copy of the GNU Affero General Public License 17 * along with this program. If not, see <https://www.gnu.org/licenses/>. 18 */ 19 20 /** 21 * \file 22 * 23 * Arranger base widget. 24 */ 25 26 #ifndef __GUI_WIDGETS_ARRANGER_H__ 27 #define __GUI_WIDGETS_ARRANGER_H__ 28 29 #include "gui/widgets/main_window.h" 30 #include "audio/position.h" 31 #include "audio/transport.h" 32 #include "utils/ui.h" 33 34 #include <gtk/gtk.h> 35 36 #define ARRANGER_WIDGET_TYPE ( \ 37 arranger_widget_get_type ()) 38 G_DECLARE_FINAL_TYPE ( 39 ArrangerWidget, 40 arranger_widget, 41 Z, ARRANGER_WIDGET, 42 GtkDrawingArea) 43 44 typedef struct _ArrangerBgWidget ArrangerBgWidget; 45 typedef struct MidiNote MidiNote; 46 typedef struct SnapGrid SnapGrid; 47 typedef struct AutomationPoint AutomationPoint; 48 49 typedef struct _GtkEventControllerMotion 50 GtkEventControllerMotion; 51 typedef struct ArrangerObject ArrangerObject; 52 typedef struct ArrangerSelections ArrangerSelections; 53 typedef struct EditorSettings EditorSettings; 54 typedef struct ObjectPool ObjectPool; 55 typedef struct _RulerWidget RulerWidget; 56 typedef enum ArrangerObjectType ArrangerObjectType; 57 typedef enum TransportDisplay TransportDisplay; 58 59 /** 60 * @addtogroup widgets 61 * 62 * @{ 63 */ 64 65 #define ARRANGER_WIDGET_GET_ACTION(arr,actn) \ 66 (arr->action == UI_OVERLAY_ACTION_##actn) 67 68 typedef enum ArrangerCursor 69 { 70 /** Invalid cursor. */ 71 ARRANGER_CURSOR_NONE, 72 ARRANGER_CURSOR_SELECT, 73 ARRANGER_CURSOR_EDIT, 74 ARRANGER_CURSOR_AUTOFILL, 75 ARRANGER_CURSOR_CUT, 76 ARRANGER_CURSOR_ERASER, 77 ARRANGER_CURSOR_AUDITION, 78 ARRANGER_CURSOR_RAMP, 79 ARRANGER_CURSOR_GRAB, 80 ARRANGER_CURSOR_GRABBING, 81 ARRANGER_CURSOR_RESIZING_L, 82 ARRANGER_CURSOR_RESIZING_L_FADE, 83 ARRANGER_CURSOR_STRETCHING_L, 84 ARRANGER_CURSOR_RESIZING_L_LOOP, 85 ARRANGER_CURSOR_RESIZING_R, 86 ARRANGER_CURSOR_RESIZING_R_FADE, 87 ARRANGER_CURSOR_STRETCHING_R, 88 ARRANGER_CURSOR_RESIZING_R_LOOP, 89 ARRANGER_CURSOR_RESIZING_UP, 90 ARRANGER_CURSOR_RESIZING_UP_FADE_IN, 91 ARRANGER_CURSOR_RESIZING_UP_FADE_OUT, 92 ARRANGER_CURSOR_GRABBING_COPY, 93 ARRANGER_CURSOR_GRABBING_LINK, 94 ARRANGER_CURSOR_RANGE, 95 ARRANGER_CURSOR_FADE_IN, 96 ARRANGER_CURSOR_FADE_OUT, 97 ARRANGER_CURSOR_RENAME, 98 } ArrangerCursor; 99 100 /** 101 * Type of arranger. 102 */ 103 typedef enum ArrangerWidgetType 104 { 105 ARRANGER_WIDGET_TYPE_TIMELINE, 106 ARRANGER_WIDGET_TYPE_MIDI, 107 ARRANGER_WIDGET_TYPE_MIDI_MODIFIER, 108 ARRANGER_WIDGET_TYPE_AUDIO, 109 ARRANGER_WIDGET_TYPE_CHORD, 110 ARRANGER_WIDGET_TYPE_AUTOMATION, 111 } ArrangerWidgetType; 112 113 #if 0 114 typedef enum ArrangerWidgetHoverType 115 { 116 ARRANGER_WIDGET_HOVER_TYPE_NONE, 117 ARRANGER_WIDGET_HOVER_TYPE_TRACK, 118 ARRANGER_WIDGET_HOVER_TYPE_TRACK_LANE, 119 ARRANGER_WIDGET_HOVER_TYPE_AUTOMATION_TRACK, 120 } ArrangerWidgetHoverType; 121 #endif 122 123 /** 124 * The arranger widget is a canvas that draws all 125 * the arranger objects it contains. 126 */ 127 typedef struct _ArrangerWidget 128 { 129 GtkDrawingArea parent_instance; 130 131 /** Type of arranger this is. */ 132 ArrangerWidgetType type; 133 134 GtkGestureDrag * drag; 135 GtkGestureMultiPress * multipress; 136 GtkGestureMultiPress * right_mouse_mp; 137 GtkEventControllerMotion * motion_controller; 138 139 /** Used when dragging. */ 140 double last_offset_x; 141 double last_offset_y; 142 143 UiOverlayAction action; 144 145 /** X-axis coordinate at start of drag. */ 146 double start_x; 147 148 /** Y-axis coordinate at start of drag. */ 149 double start_y; 150 151 /** X-axis coordinate at the start of the drag, 152 * in pixels. */ 153 double start_pos_px; 154 155 /** 156 * Whether a drag update operation started. 157 * 158 * drag_update will be skipped unless this is 159 * true or gtk_drag_check_threshold() returns 160 * true. 161 */ 162 bool drag_update_started; 163 164 /** Whether an object exists, so we can use the 165 * earliest_obj_start_pos. */ 166 int earliest_obj_exists; 167 168 /** Start Position of the earliest object 169 * at the start of the drag. */ 170 Position earliest_obj_start_pos; 171 172 /** 173 * Fade in/out position at start. 174 * 175 * Used when moving fade in/out points. 176 */ 177 Position fade_pos_at_start; 178 179 /** 180 * The object that was clicked in this drag 181 * cycle, if any. 182 * 183 * This is the ArrangerObject that was clicked, 184 * even though there could be more selected. 185 */ 186 ArrangerObject * start_object; 187 188 /** Object currently hovered. */ 189 ArrangerObject * hovered_object; 190 191 /** Whether the start object was selected before 192 * drag_begin. */ 193 int start_object_was_selected; 194 195 /** 196 * A clone of the ArrangerSelections on drag 197 * begin. 198 * 199 * When autofilling velocities, this is used to 200 * store the affected objects before editing. 201 * 202 * This must contain clones only. 203 */ 204 ArrangerSelections * sel_at_start; 205 206 /** 207 * Region on drag begin, if editing automation. 208 */ 209 ZRegion * region_at_start; 210 211 /** Selections to delete, used with the eraser 212 * tool. */ 213 ArrangerSelections * sel_to_delete; 214 215 /** Start Position of the earliest object 216 * currently. */ 217 //Position earliest_obj_pos; 218 219 /** The absolute (not snapped) Position at the 220 * start of a drag, translated from start_x. */ 221 Position start_pos; 222 223 /** The absolute (not snapped) current diff in 224 * ticks from the curr_pos to the start_pos. */ 225 double curr_ticks_diff_from_start; 226 227 /** The adjusted diff in ticks to use for moving 228 * objects starting from their cached start 229 * positions. */ 230 double adj_ticks_diff; 231 232 /** adj_ticks_diff in last cycle. */ 233 double last_adj_ticks_diff; 234 235 /** The absolute (not snapped) Position as of the 236 * current action. */ 237 Position curr_pos; 238 239 Position end_pos; ///< for moving regions 240 gboolean key_is_pressed; 241 242 /** Current hovering positions. */ 243 double hover_x; 244 double hover_y; 245 246 /** Number of clicks in current action. */ 247 int n_press; 248 249 /** Associated SnapGrid. */ 250 SnapGrid * snap_grid; 251 252 /** Whether shift button is held down. */ 253 int shift_held; 254 255 /** Whether Ctrl button is held down. */ 256 int ctrl_held; 257 258 /** Whether Alt is currently held down. */ 259 int alt_held; 260 261 gint64 last_frame_time; 262 263 /* ----- TIMELINE ------ */ 264 265 /** The number of visible tracks moved during a 266 * moving operation between tracks up to the last 267 * cycle. */ 268 int visible_track_diff; 269 270 /** The number of lanes moved during a 271 * moving operation between lanes, up to the last 272 * cycle. */ 273 int lane_diff; 274 275 /** Whether this TimelineArrangerWidget is for 276 * the PinnedTracklist or not. */ 277 int is_pinned; 278 279 /** 280 * 1 if resizing range. 281 */ 282 int resizing_range; 283 284 /** 285 * 1 if this is the first call to resize the range, 286 * so range1 can be set. 287 */ 288 int resizing_range_start; 289 290 /** Cache for chord object height, used during 291 * child size allocation. */ 292 //int chord_obj_height; 293 294 /* ----- END TIMELINE ----- */ 295 296 /* ------ MIDI (PIANO ROLL) ---- */ 297 298 /** The note currently hovering over */ 299 int hovered_note; 300 301 /* ------ END MIDI (PIANO ROLL) ---- */ 302 303 /* ------ MIDI MODIFIER ---- */ 304 305 /** 1-127. */ 306 int start_vel_val; 307 308 /** 309 * Maximum Velocity diff applied in this action. 310 * 311 * Used in drag_end to create an UndableAction. 312 * This can have any value, even greater than 127 313 * and it will be clamped when applying it to 314 * a Velocity. 315 */ 316 int vel_diff; 317 318 /* ------ END MIDI MODIFIER ---- */ 319 320 /* ------- CHORD ------- */ 321 322 /** Index of the chord being hovered on. */ 323 int hovered_chord_index; 324 325 /* ------- END CHORD ------- */ 326 327 /* --- AUDIO --- */ 328 329 /** 330 * Float value at start. 331 * 332 * Used when changing the audio region gain. 333 */ 334 float fval_at_start; 335 336 double dval_at_start; 337 338 /* --- END AUDIO --- */ 339 340 /** Px the playhead was last drawn at, so we can 341 * redraw this and the new px only when the 342 * playhead changes position. */ 343 int last_playhead_px; 344 345 /** Set to 1 to redraw. */ 346 bool redraw; 347 348 cairo_t * cached_cr; 349 350 cairo_surface_t * cached_surface; 351 352 /** Rectangle in the last call. */ 353 GdkRectangle last_rect; 354 355 /** 356 * Whether the current selections can link 357 * (ie, only regions are selected). 358 * 359 * To be set on drag begin. 360 */ 361 bool can_link; 362 363 /** Whether a rectangle is highlighted for DND. */ 364 bool is_highlighted; 365 366 /** The rectangle to highlight. */ 367 GdkRectangle highlight_rect; 368 //GdkRectangle prev_highlight_rect; 369 // 370 371 /** Last selection rectangle, used to redraw the 372 * union of the new selection and this. */ 373 GdkRectangle last_selection_rect; 374 375 /** 376 * Drag start button (primary, secondary, etc.). 377 * 378 * Can be tested against GDK_BUTTON_SECONDARY and 379 * GDK_BUTTON_PRIMARY. 380 */ 381 guint drag_start_btn; 382 383 /** 384 * Whether this is the first time the widget is 385 * drawn. 386 * 387 * This is used for loading back the scroll 388 * positions saved in the project. 389 */ 390 bool first_draw; 391 392 /** Cached setting. */ 393 TransportDisplay ruler_display; 394 395 /** 396 * Layout for drawing velocity text. 397 * 398 * TODO move to Velocity if parallel 399 * processing is needed - no need now. 400 */ 401 PangoLayout * vel_layout; 402 403 /** 404 * Layout for drawing automation point text. 405 * 406 * TODO move to AutomationPoint if parallel 407 * processing is needed - no need now. 408 */ 409 PangoLayout * ap_layout; 410 411 /** 412 * Layout for drawing audio editor text. 413 */ 414 PangoLayout * audio_layout; 415 416 #if 0 417 /** 418 * Dummy cairo surface to create new surfaces from. 419 */ 420 cairo_surface_t * dummy_surface; 421 422 /** 423 * Thread pool for drawing in the background 424 * instead of in the UI thread. 425 * 426 * The result will be applied during draw in the 427 * UI thread. 428 */ 429 GThreadPool * draw_thread_pool; 430 431 /** 432 * Object pool for ArrangerDrawTaskData. 433 * 434 * Must only be accessed from the GTK thread. 435 */ 436 ObjectPool * draw_task_obj_pool; 437 #endif 438 439 /** 440 * Cached playhead x to draw. 441 * 442 * This is used to avoid queuing drawing at x and 443 * then drawing after it (if playhead moved). The 444 * playhead will be drawn at the location it 445 * was when the draw was queued. 446 */ 447 //int queued_playhead_px; 448 449 } ArrangerWidget; 450 451 const char * 452 arranger_widget_get_type_str ( 453 ArrangerWidgetType type); 454 455 /** 456 * Creates a timeline widget using the given 457 * timeline data. 458 */ 459 void 460 arranger_widget_setup ( 461 ArrangerWidget * self, 462 ArrangerWidgetType type, 463 SnapGrid * snap_grid); 464 465 /** 466 * Sets the cursor on the arranger and all of its 467 * children. 468 */ 469 void 470 arranger_widget_set_cursor ( 471 ArrangerWidget * self, 472 ArrangerCursor cursor); 473 474 /** 475 * Wrapper of the UI functions based on the arranger 476 * type. 477 */ 478 int 479 arranger_widget_pos_to_px ( 480 ArrangerWidget * self, 481 Position * pos, 482 int use_padding); 483 484 /** 485 * Gets the cursor based on the current hover 486 * position. 487 */ 488 ArrangerCursor 489 arranger_widget_get_cursor ( 490 ArrangerWidget * self); 491 492 /** 493 * Figures out which cursor should be used based 494 * on the current state and then sets it. 495 */ 496 void 497 arranger_widget_refresh_cursor ( 498 ArrangerWidget * self); 499 500 /** 501 * Gets the corresponding scrolled window. 502 */ 503 GtkScrolledWindow * 504 arranger_widget_get_scrolled_window ( 505 ArrangerWidget * self); 506 507 /** 508 * Get all objects currently present in the arranger. 509 * 510 * @param objs Array to fill in. 511 * @param size Array size to fill in. 512 */ 513 void 514 arranger_widget_get_all_objects ( 515 ArrangerWidget * self, 516 ArrangerObject ** objs, 517 int * size); 518 519 /** 520 * Wrapper for ui_px_to_pos depending on the 521 * arranger type. 522 */ 523 void 524 arranger_widget_px_to_pos ( 525 ArrangerWidget * self, 526 double px, 527 Position * pos, 528 bool has_padding); 529 530 /** 531 * Returns the current visible rectangle. 532 * 533 * @param rect The rectangle to fill in. 534 */ 535 void 536 arranger_widget_get_visible_rect ( 537 ArrangerWidget * self, 538 GdkRectangle * rect); 539 540 /** 541 * Fills in the given array with the ArrangerObject's 542 * of the given type that appear in the given 543 * ranger. 544 * 545 * @param type The type of arranger objects to find, 546 * or -1 to look for all objects. 547 * @param x X, or -1 to not check x. 548 * @param y Y, or -1 to not check y. 549 * @param array The array to fill. 550 * @param array_size The size of the array to fill. 551 */ 552 void 553 arranger_widget_get_hit_objects_at_point ( 554 ArrangerWidget * self, 555 ArrangerObjectType type, 556 double x, 557 double y, 558 ArrangerObject ** array, 559 int * array_size); 560 561 /** 562 * Fills in the given array with the ArrangerObject's 563 * of the given type that appear in the given 564 * ranger. 565 * 566 * @param rect The rectangle to search in. 567 * @param type The type of arranger objects to find, 568 * or -1 to look for all objects. 569 * @param array The array to fill. 570 * @param array_size The size of the array to fill. 571 */ 572 void 573 arranger_widget_get_hit_objects_in_rect ( 574 ArrangerWidget * self, 575 ArrangerObjectType type, 576 GdkRectangle * rect, 577 ArrangerObject ** array, 578 int * array_size); 579 580 /** 581 * Returns the ArrangerObject of the given type 582 * at (x,y). 583 * 584 * @param type The arranger object type, or -1 to 585 * search for all types. 586 * @param x X, or -1 to not check x. 587 * @param y Y, or -1 to not check y. 588 */ 589 ArrangerObject * 590 arranger_widget_get_hit_arranger_object ( 591 ArrangerWidget * self, 592 ArrangerObjectType type, 593 const double x, 594 const double y); 595 596 void 597 arranger_widget_select_all ( 598 ArrangerWidget * self, 599 bool select, 600 bool fire_events); 601 602 /** 603 * Returns if the arranger is in a moving-related 604 * operation or starting a moving-related operation. 605 * 606 * Useful to know if we need transient widgets or 607 * not. 608 */ 609 bool 610 arranger_widget_is_in_moving_operation ( 611 ArrangerWidget * self); 612 613 /** 614 * Returns the ArrangerSelections for this 615 * ArrangerWidget. 616 */ 617 ArrangerSelections * 618 arranger_widget_get_selections ( 619 ArrangerWidget * self); 620 621 /** 622 * Queues a redraw of the whole visible arranger. 623 */ 624 void 625 arranger_widget_redraw_whole ( 626 ArrangerWidget * self); 627 628 /** 629 * Only redraws the playhead part. 630 */ 631 void 632 arranger_widget_redraw_playhead ( 633 ArrangerWidget * self); 634 635 /** 636 * Only redraws the given rectangle. 637 */ 638 void 639 arranger_widget_redraw_rectangle ( 640 ArrangerWidget * self, 641 GdkRectangle * rect); 642 643 SnapGrid * 644 arranger_widget_get_snap_grid ( 645 ArrangerWidget * self); 646 647 /** 648 * Called from MainWindowWidget because some 649 * events don't reach here. 650 */ 651 gboolean 652 arranger_widget_on_key_action ( 653 GtkWidget *widget, 654 GdkEventKey *event, 655 ArrangerWidget * self); 656 657 gboolean 658 arranger_widget_on_key_release ( 659 GtkWidget *widget, 660 GdkEventKey *event, 661 ArrangerWidget * self); 662 663 /** 664 * Scroll until the given object is visible. 665 * 666 * @param horizontal 1 for horizontal, 2 for 667 * vertical. 668 * @param up Whether scrolling up or down. 669 * @param padding Padding pixels. 670 */ 671 NONNULL 672 void 673 arranger_widget_scroll_until_obj ( 674 ArrangerWidget * self, 675 ArrangerObject * obj, 676 int horizontal, 677 int up, 678 int left, 679 double padding); 680 681 /** 682 * Toggles the mute status of the selection, based 683 * on the mute status of the selected object. 684 * 685 * This creates an undoable action and executes it. 686 */ 687 void 688 arranger_widget_toggle_selections_muted ( 689 ArrangerWidget * self, 690 ArrangerObject * clicked_object); 691 692 /** 693 * Returns the earliest possible position allowed 694 * in this arranger (eg, 1.1.0.0 for timeline). 695 */ 696 void 697 arranger_widget_get_min_possible_position ( 698 ArrangerWidget * self, 699 Position * pos); 700 701 /** 702 * Sets the highlight rectangle. 703 * 704 * @param rect The rectangle, or NULL to 705 * unset/unhighlight. 706 */ 707 void 708 arranger_widget_set_highlight_rect ( 709 ArrangerWidget * self, 710 GdkRectangle * rect); 711 712 /** 713 * Returns the EditorSettings corresponding to 714 * the given arranger. 715 */ 716 EditorSettings * 717 arranger_widget_get_editor_settings ( 718 ArrangerWidget * self); 719 720 bool 721 arranger_widget_is_playhead_visible ( 722 ArrangerWidget * self); 723 724 NONNULL 725 PURE 726 RulerWidget * 727 arranger_widget_get_ruler ( 728 ArrangerWidget * self); 729 730 /** 731 * Returns whether any arranger is in the middle 732 * of an action. 733 */ 734 bool 735 arranger_widget_any_doing_action (void); 736 737 /** 738 * Returns the playhead's x coordinate in absolute 739 * coordinates. 740 */ 741 int 742 arranger_widget_get_playhead_px ( 743 ArrangerWidget * self); 744 745 #define arranger_widget_print_action(self) \ 746 g_debug ( \ 747 "action: %s", ui_overlay_strings[self->action]) 748 749 /** 750 * Returns true if MIDI arranger and track mode 751 * is enabled. 752 */ 753 bool 754 arranger_widget_get_drum_mode_enabled ( 755 ArrangerWidget * self); 756 757 /** 758 * @} 759 */ 760 761 #endif 762