Line data Source code
1 : #pragma once
2 :
3 : #include "gui/ui_component.h"
4 : #include <functional>
5 : #include <string>
6 : #include <cstdint>
7 :
8 : namespace Amplitron {
9 :
10 16 : struct RecordingProps {
11 16 : bool is_recording = false;
12 16 : bool is_paused = false;
13 16 : bool has_unsaved = false;
14 16 : float duration = 0.0f;
15 16 : float current_peak = 0.0f;
16 16 : int64_t samples_written = 0;
17 16 : int channels = 1;
18 16 : int sample_rate = 44100;
19 :
20 : // Waveform preview (valid only while is_recording == true)
21 16 : const float* waveform_buf = nullptr;
22 16 : int waveform_size = 0;
23 :
24 : std::function<void()> on_resume;
25 : std::function<void()> on_pause;
26 : std::function<void()> on_stop; // stops recording; GuiManager then calls render_save_dialog
27 : std::function<void()> on_start;
28 : std::function<void()> on_discard;
29 : };
30 :
31 37 : struct RecordingState {
32 11 : bool needs_save = false; // true after stop/save-as is requested
33 : std::string status_msg;
34 : };
35 :
36 : /**
37 : * @brief Reactive recording controls component.
38 : *
39 : * Receives all recording state via RecordingProps from GuiManager each frame.
40 : * Communicates recording lifecycle events back through callbacks in Props;
41 : * never touches the engine or recorder directly.
42 : *
43 : * Save-dialog flow:
44 : * 1. User clicks STOP or "Save As..." → state_.needs_save set true.
45 : * 2. GuiManager polls needs_save_dialog() after render().
46 : * 3. GuiManager calls render_save_dialog(callback) which runs the native
47 : * file picker and invokes the callback with the destination path.
48 : */
49 11 : class GuiRecording : public UIComponent<RecordingProps, RecordingState> {
50 : public:
51 44 : GuiRecording() = default;
52 :
53 : /** @brief Render recording controls (start/stop/pause/waveform). */
54 : void render() override;
55 :
56 : /**
57 : * @brief Show the native "Save Recording As…" file dialog.
58 : *
59 : * Must be called by GuiManager when needs_save_dialog() returns true.
60 : * Resets the internal flag after running (so it fires exactly once).
61 : * @param on_save_done Called with the chosen path; caller writes the file.
62 : */
63 : void render_save_dialog(std::function<void(const std::string& dest)> on_save_done);
64 :
65 : /** @brief Returns true if the save dialog should be opened this frame. */
66 8 : bool needs_save_dialog() const { return state_.needs_save; }
67 : };
68 :
69 : } // namespace Amplitron
|