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