Fix zoom to cursor, trigger re-render on palette/dB changes, improve controls

Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com>
This commit is contained in:
2026-03-27 23:10:16 -07:00
parent 377ba3616a
commit 10e7a68baa
+56 -30
View File
@@ -813,20 +813,20 @@ static void DrawInfo(Rectangle bounds)
DrawText("No audio file loaded", 10, y, fontSize, RED); DrawText("No audio file loaded", 10, y, fontSize, RED);
} }
y = GetScreenHeight() - 240; y = GetScreenHeight() - 260;
DrawText("Controls:", 10, y, fontSize, LIGHTGRAY); y += 20; DrawText("Controls:", 10, y, fontSize, LIGHTGRAY); y += 20;
DrawText(" O - Open file browser", 10, y, fontSize, GRAY); y += 18; DrawText(" O - Open file browser", 10, y, fontSize, GRAY); y += 18;
DrawText(" Drag & drop WAV file", 10, y, fontSize, GRAY); y += 18; DrawText(" Drag & drop WAV file", 10, y, fontSize, GRAY); y += 18;
DrawText(" Mouse Wheel - Zoom time", 10, y, fontSize, GRAY); y += 18; DrawText(" Mouse Wheel - Zoom to cursor", 10, y, fontSize, GRAY); y += 18;
DrawText(" Alt+Drag - Pan view", 10, y, fontSize, GRAY); y += 18; DrawText(" Alt/Middle+Drag - Pan view", 10, y, fontSize, GRAY); y += 18;
DrawText(" LMB Drag - Select time", 10, y, fontSize, GRAY); y += 18; DrawText(" LMB Drag - Select time region", 10, y, fontSize, GRAY); y += 18;
DrawText(" Shift+LMB - Select freq", 10, y, fontSize, GRAY); y += 18; DrawText(" Shift+LMB - Select freq range", 10, y, fontSize, GRAY); y += 18;
DrawText(" SPACE - Play selection", 10, y, fontSize, GRAY); y += 18; DrawText(" SPACE - Play selection", 10, y, fontSize, GRAY); y += 18;
DrawText(" M - Change colormap", 10, y, fontSize, GRAY); y += 18; DrawText(" M - Cycle colormap", 10, y, fontSize, GRAY); y += 18;
DrawText(" W/S - Adjust dB floor", 10, y, fontSize, GRAY); y += 18; DrawText(" W/S - Adjust dB floor", 10, y, fontSize, GRAY); y += 18;
DrawText(" G - Toggle grid", 10, y, fontSize, GRAY); y += 18; DrawText(" G - Toggle grid", 10, y, fontSize, GRAY); y += 18;
DrawText(" R - Reset selections", 10, y, fontSize, GRAY); y += 18; DrawText(" R - Reset selections", 10, y, fontSize, GRAY); y += 18;
DrawText(" Home/End - Full view/Zoom in", 10, y, fontSize, GRAY); y += 18; DrawText(" Home - Full view, End - Zoom in", 10, y, fontSize, GRAY); y += 18;
DrawText(" ESC - Clear selections", 10, y, fontSize, GRAY); DrawText(" ESC - Clear selections", 10, y, fontSize, GRAY);
y = GetScreenHeight() - 60; y = GetScreenHeight() - 60;
@@ -917,55 +917,77 @@ int main(int argc, char* argv[])
// View controls // View controls
if (app.loaded && !app.showFileBrowser) { if (app.loaded && !app.showFileBrowser) {
// Zoom with mouse wheel Rectangle viewBounds = { 100, 50, GetScreenWidth() - 150, GetScreenHeight() - 150 };
if (CheckCollisionPointRec(GetMousePosition(), (Rectangle){ 100, 50, GetScreenWidth() - 150, GetScreenHeight() - 150 })) {
// Zoom with mouse wheel (zooms to cursor position)
if (CheckCollisionPointRec(GetMousePosition(), viewBounds)) {
int wheel = GetMouseWheelMove(); int wheel = GetMouseWheelMove();
if (wheel != 0) { if (wheel != 0) {
float viewCenter = (app.viewStart + app.viewEnd) / 2; // Calculate mouse position as normalized time (0-1)
float mouseT = (GetMousePosition().x - viewBounds.x) / viewBounds.width;
mouseT = Clamp(mouseT + app.viewStart, 0.0f, 1.0f);
float viewWidth = app.viewEnd - app.viewStart; float viewWidth = app.viewEnd - app.viewStart;
float zoomFactor = (wheel > 0) ? 0.8f : 1.2f; float zoomFactor = (wheel > 0) ? 0.8f : 1.2f;
float newWidth = viewWidth * zoomFactor; float newWidth = viewWidth * zoomFactor;
if (newWidth < 0.05f) newWidth = 0.05f; if (newWidth < 0.02f) newWidth = 0.02f;
if (newWidth > 1.0f) newWidth = 1.0f; if (newWidth > 1.0f) newWidth = 1.0f;
app.viewStart = viewCenter - newWidth / 2;
app.viewEnd = viewCenter + newWidth / 2; // Zoom around cursor position
float leftOfMouse = mouseT - app.viewStart;
float rightOfMouse = app.viewEnd - mouseT;
float newLeftOfMouse = leftOfMouse * (newWidth / viewWidth);
float newRightOfMouse = rightOfMouse * (newWidth / viewWidth);
app.viewStart = mouseT - newLeftOfMouse;
app.viewEnd = mouseT + newRightOfMouse;
// Clamp to valid range
if (app.viewStart < 0) { app.viewStart = 0; app.viewEnd = newWidth; } if (app.viewStart < 0) { app.viewStart = 0; app.viewEnd = newWidth; }
if (app.viewEnd > 1) { app.viewEnd = 1; app.viewStart = 1 - newWidth; } if (app.viewEnd > 1) { app.viewEnd = 1; app.viewStart = 1 - newWidth; }
// Invalidate texture cache
app.visibleTextureValid = false;
} }
} }
// Pan with Alt+drag // Pan with Alt+drag or middle mouse button
bool altHeld = IsKeyDown(KEY_LEFT_ALT) || IsKeyDown(KEY_RIGHT_ALT); bool canPan = IsKeyDown(KEY_LEFT_ALT) || IsKeyDown(KEY_RIGHT_ALT) || IsMouseButtonDown(MOUSE_BUTTON_MIDDLE);
if (altHeld && IsMouseButtonPressed(MOUSE_LEFT_BUTTON)) { if (canPan && IsMouseButtonPressed(MOUSE_LEFT_BUTTON)) {
app.isPanning = true; app.isPanning = true;
app.panStartPos = GetMousePosition(); app.panStartPos = GetMousePosition();
app.panStartViewStart = app.viewStart; app.panStartViewStart = app.viewStart;
app.panStartViewEnd = app.viewEnd; app.panStartViewEnd = app.viewEnd;
} }
if (app.isPanning && IsMouseButtonDown(MOUSE_LEFT_BUTTON)) { if (app.isPanning && IsMouseButtonDown(MOUSE_LEFT_BUTTON)) {
Rectangle bounds = { 100, 50, GetScreenWidth() - 150, GetScreenHeight() - 150 }; float dx = (GetMousePosition().x - app.panStartPos.x) / viewBounds.width;
if (CheckCollisionPointRec(app.panStartPos, bounds)) { float viewWidth = app.panStartViewEnd - app.panStartViewStart;
float dx = (GetMousePosition().x - app.panStartPos.x) / bounds.width; app.viewStart = app.panStartViewStart - dx * viewWidth;
float viewWidth = app.panStartViewEnd - app.panStartViewStart; app.viewEnd = app.panStartViewEnd - dx * viewWidth;
app.viewStart = app.panStartViewStart - dx * viewWidth; if (app.viewStart < 0) { app.viewStart = 0; app.viewEnd = viewWidth; }
app.viewEnd = app.panStartViewEnd - dx * viewWidth; if (app.viewEnd > 1) { app.viewEnd = 1; app.viewStart = 1 - viewWidth; }
if (app.viewStart < 0) { app.viewStart = 0; app.viewEnd = viewWidth; } app.visibleTextureValid = false;
if (app.viewEnd > 1) { app.viewEnd = 1; app.viewStart = 1 - viewWidth; }
}
} }
if (IsMouseButtonReleased(MOUSE_LEFT_BUTTON)) app.isPanning = false; if (IsMouseButtonReleased(MOUSE_LEFT_BUTTON)) app.isPanning = false;
// Home/End keys // Home/End keys
if (IsKeyPressed(KEY_HOME)) { app.viewStart = 0.0f; app.viewEnd = 1.0f; } if (IsKeyPressed(KEY_HOME)) {
app.viewStart = 0.0f; app.viewEnd = 1.0f;
app.visibleTextureValid = false;
}
if (IsKeyPressed(KEY_END)) { if (IsKeyPressed(KEY_END)) {
float newWidth = 0.1f; float newWidth = 0.1f;
app.viewStart = 0.0f; app.viewStart = 0.0f;
app.viewEnd = newWidth; app.viewEnd = newWidth;
app.visibleTextureValid = false;
} }
} }
// Other controls // Other controls
if (IsKeyPressed(KEY_G) && !app.showFileBrowser) app.showGrid = !app.showFileBrowser; if (IsKeyPressed(KEY_G) && !app.showFileBrowser) {
app.showGrid = !app.showGrid;
}
if (IsKeyPressed(KEY_R) && !app.showFileBrowser) { if (IsKeyPressed(KEY_R) && !app.showFileBrowser) {
app.timeSelectionStart = app.viewStart; app.timeSelectionStart = app.viewStart;
app.timeSelectionEnd = app.viewEnd; app.timeSelectionEnd = app.viewEnd;
@@ -975,16 +997,20 @@ int main(int argc, char* argv[])
if (IsKeyPressed(KEY_M) && !app.showFileBrowser) { if (IsKeyPressed(KEY_M) && !app.showFileBrowser) {
app.colormap = (ColormapType)((app.colormap + 1) % COLORMAP_COUNT); app.colormap = (ColormapType)((app.colormap + 1) % COLORMAP_COUNT);
GenerateColormapTexture(); GenerateColormapTexture();
if (app.stftComputed) GenerateSpectrogramTexture(&app.stft, &app.spectrogramImage, &app.spectrogramTexture);
app.visibleTextureValid = false;
} }
if (IsKeyPressed(KEY_W) && !app.showFileBrowser) { if (IsKeyPressed(KEY_W) && !app.showFileBrowser) {
app.amplitudeFloorDb += 2.0f; app.amplitudeFloorDb += 2.0f;
if (app.amplitudeFloorDb > app.amplitudeCeilingDb - 5) app.amplitudeFloorDb = app.amplitudeCeilingDb - 5; if (app.amplitudeFloorDb > app.amplitudeCeilingDb - 5) app.amplitudeFloorDb = app.amplitudeCeilingDb - 5;
if (app.stftComputed) GenerateSpectrogramTexture(&app.stft, &app.spectrogramImage, &app.spectrogramTexture); if (app.stftComputed) GenerateSpectrogramTexture(&app.stft, &app.spectrogramImage, &app.spectrogramTexture);
app.visibleTextureValid = false;
} }
if (IsKeyPressed(KEY_S) && !app.showFileBrowser) { if (IsKeyPressed(KEY_S) && !app.showFileBrowser) {
app.amplitudeFloorDb -= 2.0f; app.amplitudeFloorDb -= 2.0f;
if (app.amplitudeFloorDb < -100) app.amplitudeFloorDb = -100; if (app.amplitudeFloorDb < -100) app.amplitudeFloorDb = -100;
if (app.stftComputed) GenerateSpectrogramTexture(&app.stft, &app.spectrogramImage, &app.spectrogramTexture); if (app.stftComputed) GenerateSpectrogramTexture(&app.stft, &app.spectrogramImage, &app.spectrogramTexture);
app.visibleTextureValid = false;
} }
if (IsKeyPressed(KEY_SPACE) && !app.showFileBrowser) PlaySelectedRegion(); if (IsKeyPressed(KEY_SPACE) && !app.showFileBrowser) PlaySelectedRegion();