Raylib 3
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 

393 lines
19 KiB

//Standard lib
#include <stdlib.h> // atoi for commandline argument char to int
#include <stdio.h>
#include <string.h>
#include <unistd.h>
//Third party
#include "raylib.h"
#define RAYGUI_IMPLEMENTATION
#include "raygui.h" // Required for GUI controls
#define GUI_FILE_DIALOG_IMPLEMENTATION
#include "gui_file_dialog.h"
//Our own files
#include "constants.h"
#include "programstate.h"
#include "gui.h"
#include "jackclient.h"
#include "camera.h"
#include "draw.h"
extern ProgramState programState;
extern Effect effects[NR_OF_EFFECTS];
static int screenWidth;
static int screenHeight;
static int center;
static int bottom;
static int remember; // Helper var: Did a value change so we need to instruct a gui reposition/draw?
static float alpha; //Helper var for colors.
static Vector2 panelScroll = { 0, 0 }; //This is the current state of scrolling. It must be declared outside the loop of course
static int currentColorIndex=0;
static int currentPaletteIndex=0; //see programstate.c setColorPalette()
static int columnX; //in pixel
static const int checkboxWidth = 24;
static bool colorChoiceEditMode = false;
static bool colorPaletteEditMode = false;
static bool pitchMarkerEditMode = false;
static bool pitchMaxEditMode = false;
static bool pitchMinEditMode= false;
static int configTab = layerIndex_notes; //index from enum in constants.h
static char fileNameToLoad[512] = { 0 };
static GuiFileDialogState fileDialogState;
//"Port 00;Port 01;Port 02;Port 03;Port 04;Port 05;Port 06;Port 07;Port 08;Port 09;Port 10;Port 11;Port 12;Port 13;Port 14;Port 15;Background;Panels;Marker"
static char colorsPortsString[VIS_PORTS*9 + 25];
void init_gui() {
for (int i=0; i<VIS_PORTS; i++) {
//Only works if VIS_PORTS is below 100 ports.
snprintf(colorsPortsString+strlen(colorsPortsString), sizeof(colorsPortsString), "Port %2d;", i); //9 because the substring is 9 chars.
}
snprintf(colorsPortsString+strlen(colorsPortsString), sizeof(colorsPortsString), "Background;Panels;Marker"); //Attach to the end
fileDialogState = InitGuiFileDialog(420, 310, GetWorkingDirectory(), false);
}
bool guiIsKeyPressed(int keyConstant) {
//Wrap Raylib function to only accept input when we want it.
if (programState.lockInput) {
return false;
}
else {
return IsKeyPressed(keyConstant);
}
}
bool guiIsKeyDown(int keyConstant) {
//Wrap Raylib function to only accept input when we want it.
if (programState.lockInput) {
return false;
}
else {
return IsKeyDown(keyConstant);
}
}
void mainLoop_gui() {
//bool pressed = IsMouseButtonPressed(0) || IsMouseButtonPressed(1); //0 left, 1 right //Registers no matter where you clicked
//if (pressed) { printf("click\n"); };
GuiUnlock();
programState.lockInput = false;
if (fileDialogState.SelectFilePressed)
{
// Load image file (if supported extension)
if (IsFileExtension(fileDialogState.fileNameText, ".png"))
{
strcpy(fileNameToLoad, TextFormat("%s/%s", fileDialogState.dirPathText, fileDialogState.fileNameText));
loadBackgroundImage(fileNameToLoad, true); //also saves the path in programstate
}
fileDialogState.SelectFilePressed = false;
}
GuiFileDialog(&fileDialogState); //does nothing if not activated. This needs to be processed before the GUI locks.
if (fileDialogState.fileDialogActive) {
GuiLock();
programState.lockInput = true;
}
//Shortcuts and toggles
bool controlDown=false;
if ( guiIsKeyDown(KEY_LEFT_CONTROL) || guiIsKeyDown(KEY_RIGHT_CONTROL) ) {
controlDown = true;
}
if (controlDown && guiIsKeyPressed(KEY_S)) {
saveStateToFile();
}
if (guiIsKeyPressed(KEY_SPACE)){ toggleTransport(); }
if (guiIsKeyPressed(KEY_G) || guiIsKeyPressed(KEY_ESCAPE)) { programState.guiVisible = !programState.guiVisible; }
if (guiIsKeyPressed(KEY_B)){ programState.showPortBackground = !programState.showPortBackground; }
if (guiIsKeyPressed(KEY_P)){ programState.showPitchMarker = !programState.showPitchMarker; }
if (guiIsKeyPressed(KEY_N)){ programState.showConnectedPortnames = !programState.showConnectedPortnames; }
if (guiIsKeyPressed(KEY_C)){ programState.alwaysShowClock = !programState.alwaysShowClock; }
//Camera Controls
cameraMaybeZoom();
if (guiIsKeyPressed(KEY_R)){ cameraReset(); }
if (guiIsKeyDown(KEY_A)) { cameraLeft(); }
else if (guiIsKeyDown(KEY_D)) { cameraRight(); }
if (guiIsKeyDown(KEY_W)) { cameraUp(); }
else if (!controlDown && guiIsKeyDown(KEY_S)) { cameraDown(); }
if (guiIsKeyDown(KEY_Q)) { cameraRotateLeft(); }
else if (guiIsKeyDown(KEY_E)) { cameraRotateRight(); }
else if (guiIsKeyPressed(KEY_X)) { cameraRotate180(); }
//Undocumented because it is based on the current window size.
if (guiIsKeyPressed(KEY_F)){ ToggleFullscreen(); }
if (guiIsKeyPressed(KEY_M)){
programState.drawMode++;
if (programState.drawMode > 4) { programState.drawMode = 0;} //wrap around
programState.guiRedrawNeeded = true;
}
//Draw GUI Elements
//All position numbers are trial and error
//RayGUI draws and delievers the result in one ste. e.g. button clicked.
//The state of e.g. ComboBox index is given each time in the caller function.
//newState = GuiElement(RectPositionDimension, options, oldState);
if (programState.alwaysShowClock || programState.guiVisible) {
//DrawFPS(0,0); //Fugly!
screenWidth = GetScreenWidth(); //Changes on resize
screenHeight = GetScreenHeight(); //Changes on resize
center = screenWidth/2;
bottom = screenHeight - 2*SPACING;
//DrawText(programState.clockString, center, bottom-2*SPACING, 20, RAYWHITE); //text, x, y, int fontsize, color
DrawTextEx(GuiGetFont(), programState.clockString, (Vector2){center, bottom-2*SPACING}, 31, 1, RAYWHITE);
}
if (programState.guiVisible) {
//Clock is drawn outside of guiVisible with an individual check
//Transport Control Buttons
if (GuiButton((Rectangle){center-100-5, bottom, 100, HEIGHT}, "Rewind")) {
//No shortcut
seekToStart();
}
if (GuiButton((Rectangle){center, bottom, 205, HEIGHT}, "[Space] Play / Pause")) {
toggleTransport();
}
//Save
if (programState.filePath && programState.filePath[0] != '\0') {
if (GuiButton((Rectangle){ screenWidth-120, bottom-1*SPACING, 105, HEIGHT }, "[Ctrl+S] Save")) {
saveStateToFile();
}
}
//Quit
programState.instructedToQuit = GuiButton((Rectangle){ screenWidth-120, bottom, 105, HEIGHT }, "Quit");
int row=1;
columnX = 10; //in pixel
//Configs for all layers
//Layer Config "Tabs" Panel
DrawRectangle(columnX, row*SPACING-5, 160+230, HEIGHT+10, (Color){ 35, 40, 47, 255 });
GuiLabel((Rectangle){ columnX+checkboxWidth, row*SPACING, 105, HEIGHT }, "Show Config for"); // void GuiLabel(Rectangle bounds, const char *text);
configTab = GuiComboBox((Rectangle){ 160, row*SPACING, 200, HEIGHT }, "Music Layer;Effects;Sprites;General", configTab);
row++;
//Tab for each Layer. Begin at row=2
if (configTab == layerIndex_notes) {
remember = programState.showDrawMode;
programState.showDrawMode = GuiCheckBox((Rectangle){ columnX, row*SPACING, 20, HEIGHT }, "Enable Note Layer", programState.showDrawMode);
if (remember != programState.showDrawMode) { programState.guiRedrawNeeded = true;}
row++;
remember = programState.drawMode;
GuiLabel((Rectangle){ columnX+checkboxWidth, row*SPACING, 105, HEIGHT }, "[M] Note Layer Mode"); // void GuiLabel(Rectangle bounds, const char *text);
programState.drawMode = GuiComboBox((Rectangle){ 200, row*SPACING, 130, HEIGHT }, "Horizontal;Vertical;Grid;Meterbridge;Port Shapes;", programState.drawMode); //These need to be manually synced to draw.c drawFunctions[]
if (remember != programState.drawMode) { programState.guiRedrawNeeded = true;}
row++;
//Show Port Background Checkbox
programState.showPortBackground = GuiCheckBox((Rectangle){ columnX, row*SPACING, 20, HEIGHT }, "[B] Port Background", programState.showPortBackground);
row++;
//Show Unconnected Port Background Checkbox
programState.showPortBackgroundForUnconnected = GuiCheckBox((Rectangle){ columnX, row*SPACING, 20, HEIGHT }, "Draw unconnected Port Background", programState.showPortBackgroundForUnconnected);
row++;
//Pitch Marker
programState.showPitchMarker = GuiCheckBox((Rectangle){ columnX, row*SPACING, 20, HEIGHT }, "[P] Pitch Marker", programState.showPitchMarker);
remember = programState.pitchMarkerValue;
if (GuiSpinner((Rectangle){ 200, row*SPACING, 80, HEIGHT }, "", &programState.pitchMarkerValue, 0, 127, pitchMarkerEditMode)) pitchMarkerEditMode = !pitchMarkerEditMode; // bool GuiSpinner(Rectangle bounds, const char *text, int *value, int minValue, int maxValue, bool editMode)
//Bug in raygui. If edit mode for spinner is true the max check is not done.
if (programState.pitchMarkerValue > 127) {programState.pitchMarkerValue=127;}
if (programState.pitchMarkerValue < 0) {programState.pitchMarkerValue=0;}
if (remember != programState.pitchMarkerValue) { programState.guiRedrawNeeded = true;}
row++;
// FadeOut Mode
GuiLabel((Rectangle){ columnX+checkboxWidth, row*SPACING, 105, HEIGHT }, "Fade Out Mode"); // void GuiLabel(Rectangle bounds, const char *text);
programState.fadeOutMode = GuiComboBox((Rectangle){ 200, row*SPACING, 150, HEIGHT }, "Fixed;Tempo (bpm);Off", programState.fadeOutMode); //This needs to be manually synced to programState options
if (programState.fadeOutMode == 0) {
GuiSpinner((Rectangle){ 75+220+120, row*SPACING, 80, HEIGHT }, "Factor", &programState.fadeOutFactor, 1, 9, false); // bool GuiSpinner(Rectangle bounds, const char *text, int *value, int minValue, int maxValue, bool editMode)
//Bug in raygui. If edit mode for spinner is true the max check is not done.
if (programState.fadeOutFactor > 9) {programState.fadeOutFactor=9;}
if (programState.fadeOutFactor < 1) {programState.fadeOutFactor=1;}
}
row++;
// Show Port Names
programState.showConnectedPortnames = GuiCheckBox((Rectangle){ columnX, row*SPACING, 20, HEIGHT }, "[N] Show Connected Port Names", programState.showConnectedPortnames);
row++;
programState.includeClientInPortNameDisplay = GuiCheckBox((Rectangle){ columnX, row*SPACING, 20, HEIGHT }, "Include Client in Port Names", programState.includeClientInPortNameDisplay);
row++;
//Pitch Range Min
GuiLabel((Rectangle){ columnX+checkboxWidth, row*SPACING, 105, HEIGHT }, "Pitch Range Minimum"); // void GuiLabel(Rectangle bounds, const char *text);
remember = programState.pitchMin;
if (GuiSpinner((Rectangle){ 200, row*SPACING, 80, HEIGHT }, "", &programState.pitchMin, 0, 127, pitchMinEditMode)) pitchMinEditMode = !pitchMinEditMode; // bool GuiSpinner(Rectangle bounds, const char *text, int *value, int minValue, int maxValue, bool editMode)
//Bug in raygui. If edit mode for spinner is true the max check is not done.
if (programState.pitchMin > 127) {programState.pitchMin=127;}
if (programState.pitchMin < 0) {programState.pitchMin=0;}
if (remember != programState.pitchMin) { programState.guiRedrawNeeded = true;}
row++;
//Pitch Range Max
GuiLabel((Rectangle){ columnX+checkboxWidth, row*SPACING, 105, HEIGHT }, "Pitch Range Maximum"); // void GuiLabel(Rectangle bounds, const char *text);
remember = programState.pitchMax;
if (GuiSpinner((Rectangle){ 200, row*SPACING, 80, HEIGHT }, "", &programState.pitchMax, 0, 127, pitchMaxEditMode)) pitchMaxEditMode = !pitchMaxEditMode; // bool GuiSpinner(Rectangle bounds, const char *text, int *value, int minValue, int maxValue, bool editMode)
//Bug in raygui. If edit mode for spinner is true the max check is not done.
if (programState.pitchMax > 127) {programState.pitchMax=127;}
if (programState.pitchMax < 0) {programState.pitchMax=0;}
if (remember != programState.pitchMax) { programState.guiRedrawNeeded = true;}
//Second Column
////////////////
columnX=400;
//NOTE: GuiDropdownBox must draw after any other control that can be covered on unfolding
//Therefore no automatic rows
GuiLabel((Rectangle){ columnX, 2*SPACING, 105, HEIGHT }, "Color for");
GuiLabel((Rectangle){ columnX, 5*SPACING, 105, HEIGHT }, "Set Palette");
remember = currentPaletteIndex;
if (GuiDropdownBox((Rectangle){ columnX, 5*SPACING, 130, HEIGHT }, "Default;Random;Grayscale", &currentPaletteIndex, colorPaletteEditMode)) { colorPaletteEditMode = !colorPaletteEditMode; }
if (remember != currentPaletteIndex) { setColorPalette(currentPaletteIndex);}
//Draw last in this column
if (GuiDropdownBox((Rectangle){ columnX, 3*SPACING, 130, HEIGHT }, colorsPortsString, &currentColorIndex, colorChoiceEditMode)) colorChoiceEditMode = !colorChoiceEditMode;
//Third Column
////////////////
row = 2;
columnX=550;
row++; alpha = GuiColorBarAlpha((Rectangle){ columnX, row*SPACING, 200, HEIGHT }, (float)programState.colors[currentColorIndex].a/255.0f);
programState.colors[currentColorIndex] = Fade(programState.colors[currentColorIndex], alpha);
row++; programState.colors[currentColorIndex] = GuiColorPicker((Rectangle){ columnX, row*SPACING, 196, 192 }, programState.colors[currentColorIndex]);
char colorString[24];
sprintf(colorString, "R%i G%i B%i A%i", programState.colors[currentColorIndex].r, programState.colors[currentColorIndex].g, programState.colors[currentColorIndex].b, programState.colors[currentColorIndex].a);
GuiLabel((Rectangle){ columnX, row*SPACING+190, 105, HEIGHT }, colorString);
//Fourth Column
////////////////
row = 2;
columnX=850;
//Show keys for camera control
GuiLabel((Rectangle){ columnX, row*SPACING, 105, HEIGHT }, "Camera Controls");
row++; GuiLabel((Rectangle){ columnX, row*SPACING, 105, HEIGHT }, "[W][A][S][D] Pan");
row++; GuiLabel((Rectangle){ columnX, row*SPACING, 105, HEIGHT }, "[Q][E][X] Rotate");
row++; GuiLabel((Rectangle){ columnX, row*SPACING, 105, HEIGHT }, "[R] Reset");
row++;
//Help Label 40 per with 80 characters in the top right corner.
GuiLabel((Rectangle){ screenWidth-450, 1*SPACING, 105, HEIGHT }, "Mode Help"); // void GuiLabel(Rectangle bounds, const char *text);
Rectangle panelRec = { screenWidth-450, 2*SPACING, 410, 300 }; //What the user sees
Rectangle panelContentRec = {0, 0, 400, 500 }; //content, bigger than panelRec
Rectangle helpText = GuiScrollPanel(panelRec, panelContentRec, &panelScroll); //Rectangle GuiScrollPanel(Rectangle bounds, Rectangle content, Vector2 *scroll);
BeginScissorMode(helpText.x, helpText.y, helpText.width, helpText.height); // Begin scissor mode (define screen area for following drawing)
//GuiLabelColor((Rectangle){ panelRec.x + panelScroll.x, panelRec.y + panelScroll.y, panelContentRec.width, panelContentRec.height }, "Hallo Leute hier ist\nEin schöner Text für euch. Cool!\nUnd noch ne Zeile.", BLACK); // void GuiLabelColor(Rectangle bounds, const char *text, Color color);
GuiLabelColor((Rectangle){ panelRec.x + panelScroll.x, -4.5*SPACING + panelScroll.y, panelContentRec.width, panelContentRec.height }, programState.modeDescription, RAYWHITE); // void GuiLabelColor(Rectangle bounds, const char *text, Color color);
EndScissorMode();
}
//Effect Layer
else if (configTab == layerIndex_effects) {
//Show BG Layer Switch
remember = programState.showEffectLayer;
programState.showEffectLayer = GuiCheckBox((Rectangle){ columnX, row*SPACING, 20, HEIGHT }, "Enable Effects", programState.showEffectLayer);
if (remember != programState.showEffectLayer) { programState.guiRedrawNeeded = true;}
row++;
for (int i=0; i<NR_OF_EFFECTS; i++) {
//Enabled
remember =effects[i].enabled;
effects[i].enabled = GuiCheckBox((Rectangle){ columnX+10, row*SPACING, 20, HEIGHT }, effects[i].name, effects[i].enabled);
if (remember != effects[i].enabled) { programState.guiRedrawNeeded = true;}
//Foreground
effects[i].foreground = GuiCheckBox((Rectangle){ columnX+150, row*SPACING, 20, HEIGHT }, "in foreground", effects[i].foreground);
//Opacity
effects[i].opacity = GuiColorBarAlpha((Rectangle){ columnX+300, row*SPACING, 100, HEIGHT }, effects[i].opacity);
//Speed
effects[i].speed = GuiSlider((Rectangle){ columnX+460, row*SPACING, 100, HEIGHT }, "Speed", TextFormat("x%i", effects[i].speed), effects[i].speed, -4, 4);
//Size
effects[i].size = GuiSlider((Rectangle){ columnX+660, row*SPACING, 100, HEIGHT }, "Size", TextFormat("%i", effects[i].size), effects[i].size, 1, 8);
row++;
}
}
//General Config
else if (configTab == layerIndex_count) {
// Show Clock even when GUI is not visible
programState.alwaysShowClock = GuiCheckBox((Rectangle){ columnX, row*SPACING, 20, HEIGHT }, "[C] Clock always visible", programState.alwaysShowClock);
row++;
remember = programState.showBackgroundImageLayer;
programState.showBackgroundImageLayer = GuiCheckBox((Rectangle){ columnX, row*SPACING, 20, HEIGHT }, "Enable Background Image", programState.showBackgroundImageLayer);
if (remember != programState.showBackgroundImageLayer) { programState.guiRedrawNeeded = true;}
row++;
if (GuiButton((Rectangle){ columnX, row*SPACING, 205, HEIGHT}, "Open Image")) {
fileDialogState.fileDialogActive = true;
}
}
}
}