From 4136a6aed7930c225a8569825f5fb20036eec9f5 Mon Sep 17 00:00:00 2001 From: Nils <> Date: Wed, 23 Mar 2022 20:30:36 +0100 Subject: [PATCH] Code dump --- .gitignore | 4 + LICENSE_jReadJWrite.html | 251 +++ Makefile | 10 + camera.c | 94 + camera.h | 18 + constants.h | 52 + draw.c | 144 ++ draw.h | 36 + draw_activity.c | 99 + draw_activity.h | 6 + draw_meterbridge.c | 115 ++ draw_meterbridge.h | 6 + draw_port_grids.c | 121 ++ draw_port_grids.h | 6 + draw_xpitches_yports.c | 107 ++ draw_xpitches_yports.h | 6 + draw_xports_ypitches.c | 103 ++ draw_xports_ypitches.h | 6 + drawhelper.c | 181 ++ drawhelper.h | 14 + effect_starfield.c | 100 + effect_starfield.h | 6 + font.ttf | Bin 0 -> 714456 bytes glsl330/bloom.fs | 40 + gui.c | 393 ++++ gui.h | 7 + gui_file_dialog.h | 659 +++++++ jRead.c | 789 ++++++++ jRead.h | 134 ++ jWrite.c | 566 ++++++ jWrite.h | 218 +++ jackclient.c | 266 +++ jackclient.h | 19 + main.c | 405 +++++ nsm.h | 689 +++++++ programstate.c | 248 +++ programstate.h | 79 + raygui.h | 3734 ++++++++++++++++++++++++++++++++++++++ 38 files changed, 9731 insertions(+) create mode 100644 .gitignore create mode 100644 LICENSE_jReadJWrite.html create mode 100644 Makefile create mode 100644 camera.c create mode 100644 camera.h create mode 100644 constants.h create mode 100644 draw.c create mode 100644 draw.h create mode 100644 draw_activity.c create mode 100644 draw_activity.h create mode 100644 draw_meterbridge.c create mode 100644 draw_meterbridge.h create mode 100644 draw_port_grids.c create mode 100644 draw_port_grids.h create mode 100644 draw_xpitches_yports.c create mode 100644 draw_xpitches_yports.h create mode 100644 draw_xports_ypitches.c create mode 100644 draw_xports_ypitches.h create mode 100644 drawhelper.c create mode 100644 drawhelper.h create mode 100644 effect_starfield.c create mode 100644 effect_starfield.h create mode 100644 font.ttf create mode 100644 glsl330/bloom.fs create mode 100644 gui.c create mode 100644 gui.h create mode 100644 gui_file_dialog.h create mode 100644 jRead.c create mode 100644 jRead.h create mode 100644 jWrite.c create mode 100644 jWrite.h create mode 100644 jackclient.c create mode 100644 jackclient.h create mode 100644 main.c create mode 100644 nsm.h create mode 100644 programstate.c create mode 100644 programstate.h create mode 100644 raygui.h diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..e5dc988 --- /dev/null +++ b/.gitignore @@ -0,0 +1,4 @@ +*.out +*.gch +*.json +tgvs diff --git a/LICENSE_jReadJWrite.html b/LICENSE_jReadJWrite.html new file mode 100644 index 0000000..10029c9 --- /dev/null +++ b/LICENSE_jReadJWrite.html @@ -0,0 +1,251 @@ +? + +The Code Project Open License (CPOL) + + + + +

The Code Project Open License (CPOL) 1.02

+
+ +
+
+ +

Preamble

+

+ This License governs Your use of the Work. This License is intended to allow developers + to use the Source Code and Executable Files provided as part of the Work in any + application in any form. +

+

+ The main points subject to the terms of the License are:

+ + +

+ This License is entered between You, the individual or other entity reading or otherwise + making use of the Work licensed pursuant to this License and the individual or other + entity which offers the Work under the terms of this License ("Author").

+ +

License

+

+ THE WORK (AS DEFINED BELOW) IS PROVIDED UNDER THE TERMS OF THIS CODE PROJECT OPEN + LICENSE ("LICENSE"). THE WORK IS PROTECTED BY COPYRIGHT AND/OR OTHER APPLICABLE + LAW. ANY USE OF THE WORK OTHER THAN AS AUTHORIZED UNDER THIS LICENSE OR COPYRIGHT + LAW IS PROHIBITED.

+

+ BY EXERCISING ANY RIGHTS TO THE WORK PROVIDED HEREIN, YOU ACCEPT AND AGREE TO BE + BOUND BY THE TERMS OF THIS LICENSE. THE AUTHOR GRANTS YOU THE RIGHTS CONTAINED HEREIN + IN CONSIDERATION OF YOUR ACCEPTANCE OF SUCH TERMS AND CONDITIONS. IF YOU DO NOT + AGREE TO ACCEPT AND BE BOUND BY THE TERMS OF THIS LICENSE, YOU CANNOT MAKE ANY + USE OF THE WORK.

+ +
    +
  1. Definitions. + +
      +
    1. "Articles" means, collectively, all articles written by Author + which describes how the Source Code and Executable Files for the Work may be used + by a user.
    2. +
    3. "Author" means the individual or entity that offers the Work under the terms + of this License.
    4. +
    5. "Derivative Work" means a work based upon the Work or upon the + Work and other pre-existing works.
    6. +
    7. "Executable Files" refer to the executables, binary files, configuration + and any required data files included in the Work.
    8. +
    9. "Publisher" means the provider of the website, magazine, CD-ROM, DVD or other + medium from or by which the Work is obtained by You.
    10. +
    11. "Source Code" refers to the collection of source code and configuration files + used to create the Executable Files.
    12. +
    13. "Standard Version" refers to such a Work if it has not been modified, or + has been modified in accordance with the consent of the Author, such consent being + in the full discretion of the Author.
    14. +
    15. "Work" refers to the collection of files distributed by the Publisher, including + the Source Code, Executable Files, binaries, data files, documentation, whitepapers + and the Articles.
    16. +
    17. "You" is you, an individual or entity wishing to use the Work and exercise + your rights under this License. +
    18. +
    +
  2. + +
  3. Fair Use/Fair Use Rights. Nothing in this License is intended to + reduce, limit, or restrict any rights arising from fair use, fair dealing, first + sale or other limitations on the exclusive rights of the copyright owner under copyright + law or other applicable laws. +
  4. + +
  5. License Grant. Subject to the terms and conditions of this License, + the Author hereby grants You a worldwide, royalty-free, non-exclusive, perpetual + (for the duration of the applicable copyright) license to exercise the rights in + the Work as stated below: + +
      +
    1. You may use the standard version of the Source Code or Executable Files in Your + own applications.
    2. +
    3. You may apply bug fixes, portability fixes and other modifications obtained from + the Public Domain or from the Author. A Work modified in such a way shall still + be considered the standard version and will be subject to this License.
    4. +
    5. You may otherwise modify Your copy of this Work (excluding the Articles) in any + way to create a Derivative Work, provided that You insert a prominent notice in + each changed file stating how, when and where You changed that file.
    6. +
    7. You may distribute the standard version of the Executable Files and Source Code + or Derivative Work in aggregate with other (possibly commercial) programs as part + of a larger (possibly commercial) software distribution.
    8. +
    9. The Articles discussing the Work published in any form by the author may not be + distributed or republished without the Author's consent. The author retains + copyright to any such Articles. You may use the Executable Files and Source Code + pursuant to this License but you may not repost or republish or otherwise distribute + or make available the Articles, without the prior written consent of the Author.
    10. +
    + + Any subroutines or modules supplied by You and linked into the Source Code or Executable + Files of this Work shall not be considered part of this Work and will not be subject + to the terms of this License. +
  6. + +
  7. Patent License. Subject to the terms and conditions of this License, + each Author hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, + irrevocable (except as stated in this section) patent license to make, have made, use, import, + and otherwise transfer the Work.
  8. + +
  9. Restrictions. The license granted in Section 3 above is expressly + made subject to and limited by the following restrictions: + +
      +
    1. You agree not to remove any of the original copyright, patent, trademark, and + attribution notices and associated disclaimers that may appear in the Source Code + or Executable Files.
    2. +
    3. You agree not to advertise or in any way imply that this Work is a product of Your + own.
    4. +
    5. The name of the Author may not be used to endorse or promote products derived from + the Work without the prior written consent of the Author.
    6. +
    7. You agree not to sell, lease, or rent any part of the Work. This does not restrict + you from including the Work or any part of the Work inside a larger software + distribution that itself is being sold. The Work by itself, though, cannot be sold, + leased or rented.
    8. +
    9. You may distribute the Executable Files and Source Code only under the terms of + this License, and You must include a copy of, or the Uniform Resource Identifier + for, this License with every copy of the Executable Files or Source Code You distribute + and ensure that anyone receiving such Executable Files and Source Code agrees that + the terms of this License apply to such Executable Files and/or Source Code. You + may not offer or impose any terms on the Work that alter or restrict the terms of + this License or the recipients' exercise of the rights granted hereunder. You + may not sublicense the Work. You must keep intact all notices that refer to this + License and to the disclaimer of warranties. You may not distribute the Executable + Files or Source Code with any technological measures that control access or use + of the Work in a manner inconsistent with the terms of this License.
    10. +
    11. You agree not to use the Work for illegal, immoral or improper purposes, or on pages + containing illegal, immoral or improper material. The Work is subject to applicable + export laws. You agree to comply with all such laws and regulations that may apply + to the Work after Your receipt of the Work. +
    12. +
    +
  10. + +
  11. Representations, Warranties and Disclaimer. THIS WORK IS PROVIDED + "AS IS", "WHERE IS" AND "AS AVAILABLE", WITHOUT ANY EXPRESS OR IMPLIED WARRANTIES + OR CONDITIONS OR GUARANTEES. YOU, THE USER, ASSUME ALL RISK IN ITS USE, INCLUDING + COPYRIGHT INFRINGEMENT, PATENT INFRINGEMENT, SUITABILITY, ETC. AUTHOR EXPRESSLY + DISCLAIMS ALL EXPRESS, IMPLIED OR STATUTORY WARRANTIES OR CONDITIONS, INCLUDING + WITHOUT LIMITATION, WARRANTIES OR CONDITIONS OF MERCHANTABILITY, MERCHANTABLE QUALITY + OR FITNESS FOR A PARTICULAR PURPOSE, OR ANY WARRANTY OF TITLE OR NON-INFRINGEMENT, + OR THAT THE WORK (OR ANY PORTION THEREOF) IS CORRECT, USEFUL, BUG-FREE OR FREE OF + VIRUSES. YOU MUST PASS THIS DISCLAIMER ON WHENEVER YOU DISTRIBUTE THE WORK OR DERIVATIVE + WORKS. +
  12. + +
  13. Indemnity. You agree to defend, indemnify and hold harmless the Author and + the Publisher from and against any claims, suits, losses, damages, liabilities, + costs, and expenses (including reasonable legal or attorneys’ fees) resulting from + or relating to any use of the Work by You. +
  14. + +
  15. Limitation on Liability. EXCEPT TO THE EXTENT REQUIRED BY APPLICABLE + LAW, IN NO EVENT WILL THE AUTHOR OR THE PUBLISHER BE LIABLE TO YOU ON ANY LEGAL + THEORY FOR ANY SPECIAL, INCIDENTAL, CONSEQUENTIAL, PUNITIVE OR EXEMPLARY DAMAGES + ARISING OUT OF THIS LICENSE OR THE USE OF THE WORK OR OTHERWISE, EVEN IF THE AUTHOR + OR THE PUBLISHER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. +
  16. + +
  17. Termination. + +
      +
    1. This License and the rights granted hereunder will terminate automatically upon + any breach by You of any term of this License. Individuals or entities who have + received Derivative Works from You under this License, however, will not have their + licenses terminated provided such individuals or entities remain in full compliance + with those licenses. Sections 1, 2, 6, 7, 8, 9, 10 and 11 will survive any termination + of this License.
    2. + +
    3. If You bring a copyright, trademark, patent or any other infringement claim against + any contributor over infringements You claim are made by the Work, your License + from such contributor to the Work ends automatically.
    4. + +
    5. Subject to the above terms and conditions, this License is perpetual (for the duration + of the applicable copyright in the Work). Notwithstanding the above, the Author + reserves the right to release the Work under different license terms or to stop + distributing the Work at any time; provided, however that any such election will + not serve to withdraw this License (or any other license that has been, or is required + to be, granted under the terms of this License), and this License will continue + in full force and effect unless terminated as stated above. +
    6. +
    +
  18. + +
  19. Publisher. The parties hereby confirm that the Publisher shall + not, under any circumstances, be responsible for and shall not have any liability + in respect of the subject matter of this License. The Publisher makes no warranty + whatsoever in connection with the Work and shall not be liable to You or any party + on any legal theory for any damages whatsoever, including without limitation any + general, special, incidental or consequential damages arising in connection to this + license. The Publisher reserves the right to cease making the Work available to + You at any time without notice
  20. + +
  21. Miscellaneous + +
      +
    1. This License shall be governed by the laws of the location of the head office of + the Author or if the Author is an individual, the laws of location of the principal + place of residence of the Author.
    2. +
    3. If any provision of this License is invalid or unenforceable under applicable law, + it shall not affect the validity or enforceability of the remainder of the terms + of this License, and without further action by the parties to this License, such + provision shall be reformed to the minimum extent necessary to make such provision + valid and enforceable.
    4. +
    5. No term or provision of this License shall be deemed waived and no breach consented + to unless such waiver or consent shall be in writing and signed by the party to + be charged with such waiver or consent.
    6. +
    7. This License constitutes the entire agreement between the parties with respect to + the Work licensed herein. There are no understandings, agreements or representations + with respect to the Work not specified herein. The Author shall not be bound by + any additional provisions that may appear in any communication from You. This License + may not be modified without the mutual written agreement of the Author and You. +
    8. +
    + +
  22. +
+ +
+
+ + + diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..480b007 --- /dev/null +++ b/Makefile @@ -0,0 +1,10 @@ + +.PHONY: clean + +all: + gcc -o tgvs main.c draw.c gui.c jackclient.c drawhelper.c draw_xpitches_yports.c draw_xports_ypitches.c draw_port_grids.c draw_meterbridge.c draw_activity.c programstate.c jRead.c jWrite.c camera.c effect_starfield.c -lraylib -lGL -lm -lpthread -ldl -lrt -lX11 -ljack -llo + + +clean: + rm tgvs + rm *.gch diff --git a/camera.c b/camera.c new file mode 100644 index 0000000..a34602e --- /dev/null +++ b/camera.c @@ -0,0 +1,94 @@ +//Standard lib + +//Third party +#include "raylib.h" + +//Our own files +#include "constants.h" +#include "programstate.h" +#include "camera.h" + +extern ProgramState programState; + + +// https://www.raylib.com/examples/web/core/loader.html?name=core_2d_camera +//Camera controls, such as zoom and reset, are in gui.c + +static int screenWidth; +static int screenHeight; + +void cameraMoveUpdate() { + programState.camera.offset = (Vector2){ screenWidth/2+programState.cameraCenterOnX, screenHeight/2+programState.cameraCenterOnY }; +} + +void cameraLeft() { + programState.cameraCenterOnX -= 10; + cameraMoveUpdate(); +} +void cameraRight() { + programState.cameraCenterOnX += 10; + cameraMoveUpdate(); +} +void cameraUp() { + programState.cameraCenterOnY -= 10; + cameraMoveUpdate(); +} +void cameraDown() { + programState.cameraCenterOnY += 10; + cameraMoveUpdate(); +} + +void cameraMaybeZoom() { + //float rememberZoom = programState.camera.zoom; + if (!programState.lockInput) { + programState.camera.zoom += ((float)GetMouseWheelMove()*0.05f); + if (programState.camera.zoom < 0) + programState.camera.zoom = 0.0f; + //if (rememberZoom != programState.camera.zoom) {} + } +} + +void cameraReset() { + //Only called through user action. Camera startup values are either loaded from file or set in programstate.c + programState.camera.zoom = 1.0f; + programState.camera.rotation = 0.0f; + programState.cameraCenterOnX = 0; + programState.cameraCenterOnY = 0; + cameraMoveUpdate(); +} + +void cameraNormalizeRotation() { + if (programState.camera.rotation > 359) programState.camera.rotation -= 360; + else if (programState.camera.rotation < 0) programState.camera.rotation += 360; +} + +void cameraRotateLeft() { + programState.camera.rotation--; + cameraNormalizeRotation(); +} + +void cameraRotateRight() { + programState.camera.rotation++; + cameraNormalizeRotation(); +} + +void cameraRotate180() { + programState.camera.rotation += 180.0f; + cameraNormalizeRotation(); +} + +void cameraFlip() { + programState.camera.zoom *= -1.0f; //this is the same as rotation by 180, and not mirror + //programState.camera.rotation += 180.0f; +} + +void mainLoop_cameraReposition() { + if (programState.guiRedrawNeeded) { + screenWidth = GetScreenWidth(); //Changes on resize + screenHeight = GetScreenHeight(); //Changes on resize + programState.camera.target = (Vector2){ screenWidth/2, screenHeight/2 }; + programState.camera.offset = (Vector2){ screenWidth/2+programState.cameraCenterOnX, screenHeight/2+programState.cameraCenterOnY }; + } +} + + diff --git a/camera.h b/camera.h new file mode 100644 index 0000000..904f94a --- /dev/null +++ b/camera.h @@ -0,0 +1,18 @@ +#ifndef CAMERA_H +#define CAMERA_H + +void cameraReset(); +void cameraMaybeZoom(); +void mainLoop_cameraReposition(); +void cameraRotateLeft(); +void cameraRotateRight(); +void cameraRotate180(); +//void cameraFlip(); + +void cameraLeft(); +void cameraRight(); +void cameraUp(); +void cameraDown(); + + +#endif // not defined CAMERA_H diff --git a/constants.h b/constants.h new file mode 100644 index 0000000..fa9e4e2 --- /dev/null +++ b/constants.h @@ -0,0 +1,52 @@ +#ifndef CONSTANTS_H +#define CONSTANTS_H + +#include "raylib.h" + +#ifndef MAX +#define MAX(a,b) ( (a) < (b) ? (b) : (a) ) +#endif + +#define VIS_PORTS 16 // Program is able to handle <100 ports. But we never intend anything different than 16 to be honest. +#define VIS_PORTS_SQRT 4 //please choose by hand. If not possibe choose the next higher. e.g. 13 ports -> 4² + +//Pixel values +#define NOTE_SMALL_SIDE 14 +#define NOTE_LONG_SIDE 20 +#define NOTE_BORDER 4 //halved for left/right padding. the NOTE sides already include the border. +#define NOTE_GAP 3 +//For GUI +#define HEIGHT 25 +#define SPACING 35 + + +typedef struct { // C-N00b: using typedef lets us type Note nt; or (Note){...} instead of struct Note. + int active; + int port; + int x; + int y; + int pitch; + int velocity; //converted to color, size etc. by raylib + float countdown; //0.0f is not existent, 1 is permanently visible, everything between is the fade out process with auto-decrement. To start the timer set to 0.999 or so +} Note; + + +enum { + //ports are 0-15 + background=VIS_PORTS+0, + backgroundLight=VIS_PORTS+1, + backgroundLighter=VIS_PORTS+2, + }; + + +enum { + //Layers in order. + layerIndex_notes, + layerIndex_effects, + layerIndex_sprites, + layerIndex_count, //last one +}; + +#endif // not defined CONSTANTS_H + + diff --git a/draw.c b/draw.c new file mode 100644 index 0000000..be168f3 --- /dev/null +++ b/draw.c @@ -0,0 +1,144 @@ +//Standard lib +#include +#include +#include +#include + +//Third party +#include "raylib.h" + +//Our own files +#include "constants.h" +#include "programstate.h" +#include "drawhelper.h" +#include "draw.h" + +//Drawing Routines +#include "draw_xpitches_yports.h" +#include "draw_xports_ypitches.h" +#include "draw_port_grids.h" +#include "draw_meterbridge.h" +#include "draw_activity.h" + +//Effect Routines +#include "effect_starfield.h" + +#define GLSL_VERSION 330 + + +extern ProgramState programState; + +Effect effects[NR_OF_EFFECTS] = { + { false, "Starfield", false, 1.0f, 1, 2, effect_starfield}, + { false, "Snow Fall", false, 1.0f, 1, 3, effect_starfield}, + { false, "Falling Leafs", false, 1.0f, 1, 4, effect_starfield}, + { false, "Rain", false, 1.0f, 1, 5, effect_starfield}, + { false, "Embers", false, 1.0f, 1, 5, effect_starfield}, +}; + +//This needs to be manually synced to gui.c combox +//This order is permanent. No re-ordering after the first release! +//The save file and the GUI depend on it. +void (*drawFunctions[5])() = { + draw_xpitches_yports, + draw_xports_ypitches, + draw_port_grids, + draw_meterbridge, + draw_activity, + }; + + +static Texture2D backgroundTexture; +static RenderTexture2D renderTarget; +static Shader shader; + +void loadBackgroundImage(char * path, bool newImage) { + if (programState.nsm) { + char * temporaryAbsolutePath = malloc (sizeof(char) * 4096); //4096 is the max path length in linux + snprintf(temporaryAbsolutePath, (sizeof(char) * 4096), "%s/%s", programState.nsmDirectory, "background.png"); + if (newImage) { //User clicked on the GUI button and chose a file + unlink(temporaryAbsolutePath); + symlink(path, temporaryAbsolutePath); //source-file, link + } + programState.pathBackgroundImage = "background.png"; + backgroundTexture = LoadTexture(temporaryAbsolutePath); + free(temporaryAbsolutePath); + } + else { + programState.pathBackgroundImage = path; + backgroundTexture = LoadTexture(programState.pathBackgroundImage); + } + +} + +void init_draw() { + renderTarget = LoadRenderTexture(GetScreenWidth(), GetScreenHeight()); + shader = LoadShader(0, FormatText("glsl%i/bloom.fs", GLSL_VERSION)); //vs file, fs file +} + + +void mainLoop_draw(Note *allGUINotes) { + if (IsWindowResized()) { + //printf("Window resized to: %i x %i\n", GetScreenWidth(), GetScreenHeight()); + programState.guiRedrawNeeded = true; + } + + //Drawing Layers from bottom to top: + //Background Image (or plain color) + //Background Sprites (internal Z-Order = Y) + //Background Effects (e.g. Starfield) + //Main Visualization (Notes) + //Foreground Sprites (internal Z-Order = Y) + //Foreground Effects (e.g. Rain) + + + + + if (programState.showBackgroundImageLayer) { + //void DrawTexture(Texture2D texture, int posX, int posY, Color tint); + //Draw centered but not scaled. + DrawTexture(backgroundTexture, GetScreenWidth()/2-backgroundTexture.width/2, GetScreenHeight()/2-backgroundTexture.height/2, WHITE); + } + + //BeginTextureMode(renderTarget); // Enable drawing to texture + //ClearBackground(BLACK); //Texture background + + //Background Effects Pass + if (programState.showEffectLayer) { + for (int i=0; i +#include + +//Third party +#include "raylib.h" + +//Our own files +#include "constants.h" +#include "programstate.h" +#include "drawhelper.h" +#include "draw_activity.h" + + +static int screenWidth; +static int screenHeight; + +static int radius = 80; +const float distanceFactor = 2.5; +static int xOffset; +static int yOffset; + +extern ProgramState programState; + +static float fadeout[VIS_PORTS]; + + +static void reposition(Note *allGUINotes) { + //This is both init and update. We only call it internally, the name of the function doesn't matter. + //Once guaranteed called on program start and then each window resize + screenWidth = GetScreenWidth(); + screenHeight = GetScreenHeight(); + + xOffset = (int)(screenWidth/2) - (VIS_PORTS_SQRT/2)*radius*distanceFactor; + yOffset = (int)(screenHeight/2) - (VIS_PORTS_SQRT/2)*radius*distanceFactor; + + programState.modeDescription = "Each port is one polygon.\nNumber of sites equals active notes.\nThere is no time-dimension."; +} + + +void drawShape(Vector2 center, int port, float rotation) { + //DrawPolyLines(Vector2 center, int sides, float radius, float rotation, Color color); + + //float fadeValue = pow(sinf(rotation / 180 * PI), 2); //sine wants radians, not degree + //float fadeValue = (float)(GetRandomValue(1,10)-5.0f) / 100.0f + 1.0f; //sparkle + //Color color = Fade(programState.colors[port], fadeValue); + + Color border = Fade(BLACK, fadeout[port]); + Color color = Fade(programState.colors[port], fadeout[port]); + + if (programState.portActivity[port] < 3) { + //DrawCircleV(Vector2 center, float radius, Color color); + DrawCircleV(center, radius*0.7+NOTE_BORDER, border); + DrawCircleV(center, radius*0.7, color); + } + else { + DrawPoly(center, programState.portActivity[port], radius+NOTE_BORDER*2, rotation, border); + DrawPoly(center, programState.portActivity[port], radius, rotation, color); + } +} + +void draw_activity(Note *allGUINotes, int redrawNeeded) { + float ft = GetFrameTime(); + int bpmFactor = programState.bpm/40 * programState.bpm/20; //exponential curve. The higher bpm the faster we get. Below 90 it should feel really slow + float rotation = fmod(GetTime() * bpmFactor * 5, 360.0f); + + if (redrawNeeded) { + reposition(allGUINotes); + } + + for (int port=0; port 0) { + //printf("port %i notes %i\n", port, programState.portActivity[port]); + fadeout[port] = 1.0f; + drawShape(center, port, rotation); + + } + else if (fadeout[port] > 0.0f) { + if (fadeout[port] == 1.0f) { fadeout[port] = 0.999; } //begin countdown + fadeout[port] = calculateCountdown(fadeout[port], ft); + drawShape(center, port, rotation); + } + + if (programState.showConnectedPortnames) { + drawJackPortName(programState.connectedPortNames[port], xOffset+blockX, yOffset+blockY, 18, RAYWHITE, false); //text, x, y, int fontsize, color, vertical + } + } +} diff --git a/draw_activity.h b/draw_activity.h new file mode 100644 index 0000000..ac878f5 --- /dev/null +++ b/draw_activity.h @@ -0,0 +1,6 @@ +#ifndef DRAW_ACTIVITY_H +#define DRAW_ACTIVITY_H + +void draw_activity(Note *allGUINotes, int redrawNeeded); + +#endif // not defined DRAW_ACTIVITY_H diff --git a/draw_meterbridge.c b/draw_meterbridge.c new file mode 100644 index 0000000..0ea3553 --- /dev/null +++ b/draw_meterbridge.c @@ -0,0 +1,115 @@ +//Standard lib +#include + +//Third party +#include "raylib.h" +#include "raygui.h" // Required for GUI controls + +//Our own files +#include "constants.h" +#include "programstate.h" +#include "drawhelper.h" +#include "draw_meterbridge.h" + +extern ProgramState programState; +static Rectangle backgroundRect; +static bool guiGroupEditMode= false; +static int screenHeight; +static int bottom; + +static void reposition(Note *allGUINotes) { + //This is both init and update. We only call it internally, the name of the function doesn't matter. + //Once guaranteed called on program start and then each window resize + int screenWidth = GetScreenWidth(); + int screenHeight = GetScreenHeight(); + int xOffset = (int)(screenWidth/2) - (int)(60*(NOTE_LONG_SIDE+NOTE_GAP)); //we want all tracks around the center. + int yOffset = (int)(screenHeight/2) - (int)(NOTE_SMALL_SIDE+NOTE_GAP)*2; //we want all tracks below the center. + + programState.modeDescription = "All port are in one horizontal row.\ +\nPitches are left to right, low to high.\ +\n\ +\nVelocity 'shoots' notes upwards, then they fall back\ +\ninfluenced by the fade-out setting.\ +\n\ +\nYou can set the a 'grouping' parameter for this mode\ +\nwhich combines several pitches into a single indicator.\ +\nGrouping uses the pitch marker pitch as baseline.\ +\nThink of it like the tonic or root note.\ +\n\ +\n\ +\nNotes are only lit up when they are played.\ +\nThere is no time-dimension."; + + int rootNote = programState.pitchMarkerValue % 12; //factor out the octave. used to start groups on the pitchmarker as root note of the scale + int xpos = xOffset; + int pitchToTheCenter = 64 - (128/programState.meterbridge_grouping/2); + for (int port=0; portx, nt->y+NOTE_SMALL_SIDE, NOTE_LONG_SIDE-NOTE_BORDER, NOTE_SMALL_SIDE-NOTE_BORDER}; //TODO: Ha! :) This falls down as well, together with the note. + DrawRectangleRounded(rec, 0.5, 8, programState.colors[backgroundLighter]); + } + + //Debug: Show 0 and 127 + //DrawLine(allGUINotes[0].x, 0, allGUINotes[0].x, GetScreenHeight(), RAYWHITE); //(int startPosX, int startPosY, int endPosX, int endPosY, Color color); + //DrawLine(allGUINotes[127].x, 0, allGUINotes[127].x, GetScreenHeight(), RAYWHITE); //(int startPosX, int startPosY, int endPosX, int endPosY, Color color); + + for (int port=0; portactive) { + nt->y = backgroundRect.y - 2*(nt->countdown * nt->velocity); //Shift the notes upwards. Don't use -= or +=, that is exponential modifications + reduceCountdown(nt, ft/2); //handles 0.0 and 1.0 as special cases + drawNoteRect(nt, 1, 0); //note, rotated, square. Will not draw if not active/countdown == 0 + } + } + } + + //Our own GUI section + if (programState.guiVisible) { + EndMode2D(); //We are already in camera mode because this is a draw_ function. GUI is not under camera control. + int row = 0; + screenHeight = GetScreenHeight(); //Changes on resize + bottom = screenHeight - 2*SPACING; + int remember = programState.meterbridge_grouping; + GuiLabel((Rectangle){ 34, bottom-row*SPACING, 105, HEIGHT }, "Meterbridge Note Grouping"); // void GuiLabel(Rectangle bounds, const char *text); + if (GuiSpinner((Rectangle){ 250, bottom-row*SPACING, 80, HEIGHT }, "", &programState.meterbridge_grouping, 0, 127, guiGroupEditMode)) guiGroupEditMode = !guiGroupEditMode; // bool GuiSpinner(Rectangle bounds, const char *text, int *value, int minValue, int maxValue, bool editMode) + if (programState.meterbridge_grouping > 128) {programState.meterbridge_grouping=128;} + if (programState.meterbridge_grouping < 1) {programState.meterbridge_grouping=1;} + if (remember != programState.meterbridge_grouping) { reposition(allGUINotes); } //we cannot set guiRedrawNeeded to true here because parent draw() will reset it after we return + + row++; + BeginMode2D(programState.camera); //Switch back to previously active camera mode + } +} diff --git a/draw_meterbridge.h b/draw_meterbridge.h new file mode 100644 index 0000000..a4dc135 --- /dev/null +++ b/draw_meterbridge.h @@ -0,0 +1,6 @@ +#ifndef DRAW_METERBRIDGE_H +#define DRAW_METERBRIDGE_H + +void draw_meterbridge(Note *allGUINotes, int redrawNeeded); + +#endif // not defined DRAW_METERBRIDGE_H diff --git a/draw_port_grids.c b/draw_port_grids.c new file mode 100644 index 0000000..c24cab5 --- /dev/null +++ b/draw_port_grids.c @@ -0,0 +1,121 @@ +//Standard lib +#include + +//Third party +#include "raylib.h" + +//Our own files +#include "constants.h" +#include "programstate.h" +#include "drawhelper.h" +#include "draw_port_grids.h" + +/* Each port is a grid square, ordered in rows, like text + * Pitches are put on a 12x12 square for octaves. + * The screen does not move or scroll. Notes fade out and make room for the next note-on. + */ + +extern ProgramState programState; + +static Rectangle backgroundRects[VIS_PORTS]; // 4 floats: x, y, w, h + +static void reposition(Note *allGUINotes) { + //This is both init and update. We only call it internally, the name of the function doesn't matter. + //Once guaranteed called on program start and then each window resize + int screenWidth = GetScreenWidth(); + int screenHeight = GetScreenHeight(); + int blockSize = 13 * (NOTE_SMALL_SIDE + NOTE_GAP); //space the blocks one row/column apart = 13 + int xOffset = (int)(screenWidth/2) - (VIS_PORTS_SQRT/2)*blockSize; //shift half of the grid blocks from the center to the left + int yOffset = (int)(screenHeight/2) - (VIS_PORTS_SQRT/2)*blockSize; //shift half of the grid blocks from the center to the left + + //top left corner of each block + int blockX; + int blockY; + int portRow; + int portColumn; + int pitchRow; + int pitchColumn; + + programState.modeDescription = "Each port is one grid.\ +\nEach pitch is one square, from top left\nto bottom right.\ +\nPitch rows wrap, just like normal text.\n\n\ +\n\ +The higher the velocity of a note the more\nvibrant its color.\n\ +\n\ +Notes are only lit up when they are played.\n\ +There is no time-dimension."; + + for (int port=0; port= grid blocks available for all notes + //But we will never try to access more notes than exist in allGUINotes. + portRow = port / VIS_PORTS_SQRT; + portColumn = port % VIS_PORTS_SQRT; + blockY = portRow * blockSize; + blockX = portColumn * blockSize; + + backgroundRects[port].x = (float)(xOffset + blockX); + backgroundRects[port].y = (float)(yOffset + blockY); + backgroundRects[port].width = (float)(12 * (NOTE_SMALL_SIDE + NOTE_GAP)); //blocksize without filling the extra gap + backgroundRects[port].height = (float)(12 * (NOTE_SMALL_SIDE + NOTE_GAP)); + //Build a 12x12 Grid for octaves. + for (int midiPitch=0; midiPitch<128; midiPitch++) { + pitchRow = midiPitch / 12 +1; //shift one down because it is prettier + pitchColumn = midiPitch % 12; + allGUINotes[port*128 + midiPitch].x = xOffset + blockX + pitchColumn * (NOTE_SMALL_SIDE + NOTE_GAP); + allGUINotes[port*128 + midiPitch].y = yOffset + blockY + pitchRow * (NOTE_SMALL_SIDE + NOTE_GAP); + } + } +} + +static void drawBackground() { + //Each port is one track + //The background rects already have their positions and dimensions set. + if (programState.showPortBackground) { + for (int port=0; portx, nt->y-1.5*(NOTE_SMALL_SIDE + NOTE_GAP), 18, RAYWHITE, false); //text, x, y, int fontsize, color, vertical + } + } + + if (programState.showPitchMarker) { + //Each block has a pitch marker at one note that we draw with a different color. + //We use the already set note positions but create a background note behind the real one. + for (int port=0; portx, nt->y, NOTE_SMALL_SIDE-NOTE_BORDER, NOTE_SMALL_SIDE-NOTE_BORDER}; + DrawRectangleRounded(rec, 0.5, 8, programState.colors[backgroundLighter]); + } + } + } + + for (int port=0; portactive) { + reduceCountdown(nt, ft); //handles 0.0 and 1.0 as special cases + drawNoteRect(nt, 0, 1); //note, rotated, square. Will not draw if not active/countdown == 0 + } + } + } +} diff --git a/draw_port_grids.h b/draw_port_grids.h new file mode 100644 index 0000000..e825060 --- /dev/null +++ b/draw_port_grids.h @@ -0,0 +1,6 @@ +#ifndef DRAW_PORT_GRIDS_H +#define DRAW_PORT_GRIDS_H + +void draw_port_grids(Note *allGUINotes, int redrawNeeded); + +#endif // not defined DRAW_PORT_GRIDS_H diff --git a/draw_xpitches_yports.c b/draw_xpitches_yports.c new file mode 100644 index 0000000..8243131 --- /dev/null +++ b/draw_xpitches_yports.c @@ -0,0 +1,107 @@ +//Standard lib +#include + +//Third party +#include "raylib.h" + +//Our own files +#include "constants.h" +#include "programstate.h" +#include "drawhelper.h" +#include "draw_xpitches_yports.h" + +/* Each port is a track, which are ordered top to bottom + * Each pitch is a rectangle in that track. midi note 0 on the left to 127 on the right. + * The screen does not move or scroll. Notes fade out and make room for the next note-on. + */ + +extern ProgramState programState; + +static Rectangle backgroundRects[VIS_PORTS]; // 4 floats: x, y, w, h + +static void reposition(Note *allGUINotes) { + //This is both init and update. We only call it internally, the name of the function doesn't matter. + //Once guaranteed called on program start and then each window resize + int screenWidth = GetScreenWidth(); + int screenHeight = GetScreenHeight(); + int xOffset = (int)(screenWidth/2) - (int)(60*(NOTE_SMALL_SIDE+NOTE_GAP)); //we want all tracks around the center. + int yOffset = (int)(screenHeight/2) - (int)(VIS_PORTS*(NOTE_LONG_SIDE+NOTE_GAP))/2; //we want all tracks around the center. + + programState.modeDescription = "Each port is a horizontal track.\n\ +Each pitch is one square, going from left lowest\nto right highest.\n\ +\n\ +The higher the velocity of a note the more\nvibrant its color.\n\ +\n\ +Notes are only lit up when they are played.\n\ +There is no time-dimension."; + + + for (int port=0; portx, nt->y, 18, RAYWHITE, false); //text, x, y, int fontsize, color, vertical + } + } + + if (programState.showPitchMarker) { + for (int port=0; portx, nt->y, NOTE_SMALL_SIDE-NOTE_BORDER, NOTE_LONG_SIDE-NOTE_BORDER}; + DrawRectangleRounded(rec, 0.5, 8, programState.colors[backgroundLighter]); + } + } + } + + //Debug: Show 0 and 127 + //DrawLine(allGUINotes[0].x, 0, allGUINotes[0].x, GetScreenHeight(), RAYWHITE); //(int startPosX, int startPosY, int endPosX, int endPosY, Color color); + //DrawLine(allGUINotes[127].x, 0, allGUINotes[127].x, GetScreenHeight(), RAYWHITE); //(int startPosX, int startPosY, int endPosX, int endPosY, Color color); + + for (int port=0; portactive) { + reduceCountdown(nt, ft); //handles 0.0 and 1.0 as special cases + drawNoteRect(nt, 0, 0); //note, rotated, square. Will not draw if countdown == 0 + } + } + } +} diff --git a/draw_xpitches_yports.h b/draw_xpitches_yports.h new file mode 100644 index 0000000..02d3b32 --- /dev/null +++ b/draw_xpitches_yports.h @@ -0,0 +1,6 @@ +#ifndef DRAW_XPITCHES_YPORTS_H +#define DRAW_XPITCHES_YPORTS_H + +void draw_xpitches_yports(Note *allGUINotes, int redrawNeeded); + +#endif // not defined DRAW_XPITCHES_YPORTS_H diff --git a/draw_xports_ypitches.c b/draw_xports_ypitches.c new file mode 100644 index 0000000..227d955 --- /dev/null +++ b/draw_xports_ypitches.c @@ -0,0 +1,103 @@ +//Standard lib + +//Third party +#include "raylib.h" + +//Our own files +#include "constants.h" +#include "programstate.h" +#include "drawhelper.h" +#include "draw_xports_ypitches.h" + +/* Each port is a column, ordered from left to right + * Each pitch is a rectangle in that column. midi note 0 on the bottom to 127 on top + * The screen does not move or scroll. Notes fade out and make room for the next note-on. + */ + +extern ProgramState programState; + +static Rectangle backgroundRects[VIS_PORTS]; // 4 floats: x, y, w, h + +static void reposition(Note *allGUINotes) { + //This is both init and update. We only call it internally, the name of the function doesn't matter. + //Once guaranteed called on program start and then each window resize + int screenWidth = GetScreenWidth(); + int screenHeight = GetScreenHeight(); + int xOffset = (int)(screenWidth/2) - (int)((VIS_PORTS*NOTE_LONG_SIDE)/2); + //int yOffset = -1 * ((int)(screenWidth/2) - ((programState.pitchMax - programState.pitchMin +1 ) * NOTE_SMALL_SIDE))/2; + int yOffset = -1 * ((int)(screenHeight/2) - (60 * NOTE_SMALL_SIDE)/2); //we want all tracks around the center. + + programState.modeDescription = "Each port is a vertical column.\n\ +Each pitch is one square, going from top highest\nto bottomw lowest.\n\ +\n\ +The higher the velocity of a note the more\nvibrant its color.\n\ +\n\ +Notes are only lit up when they are played.\n\ +There is no time-dimension."; + + for (int port=0; portx, nt->y+20, 18, RAYWHITE, true); //text, x, y, int fontsize, color, vertical + } + } + + if (programState.showPitchMarker) { + for (int port=0; portx, nt->y, NOTE_LONG_SIDE-NOTE_BORDER, NOTE_SMALL_SIDE-NOTE_BORDER}; + DrawRectangleRounded(rec, 0.5, 8, programState.colors[backgroundLighter]); + } + } + } + + + for (int port=0; portactive) { + reduceCountdown(nt, ft); //handles 0.0 and 1.0 as special cases + drawNoteRect(nt, 1, 0); //note, rotated, square. Will not draw if countdown == 0 + } + + } + } +} diff --git a/draw_xports_ypitches.h b/draw_xports_ypitches.h new file mode 100644 index 0000000..4ceb749 --- /dev/null +++ b/draw_xports_ypitches.h @@ -0,0 +1,6 @@ +#ifndef DRAW_XPORTS_YPITCHES_H +#define DRAW_XPORTS_YPITCHES_H + +void draw_xports_ypitches(Note *allGUINotes, int redrawNeeded); + +#endif // not defined DRAW_XPORTS_YPITCHES_H diff --git a/drawhelper.c b/drawhelper.c new file mode 100644 index 0000000..88246de --- /dev/null +++ b/drawhelper.c @@ -0,0 +1,181 @@ +//Standard lib +#include //strchr +#include //print error messages + +//Third party +#include "raylib.h" + +//Our own files +#include "constants.h" +#include "programstate.h" +#include "drawhelper.h" + +extern ProgramState programState; + + +float intToHue(int number, int maxnumber) { + //previously used to auto-color ports this is now only used for the default port colors. + + //portnum is 0-VIS_PORTS + //hue is 0-360 + //return (input-inputLowest) / (inputHighest-inputLowest) * (outputHighest-outputLowest) + outputLowest + return (float)number / (float)maxnumber * 360.0f; +} + +Color intToColor(int number, int maxnumber) { + Color result; + Vector3 hsv; // 3 floats: hue/color, saturation, value/brightness + + hsv = (Vector3){intToHue(number, VIS_PORTS), 1.0f, (float)(127+40)/(float)167}; //Saturation is always 1, we tweak Value to never go into the black range. + result = ColorFromHSV(hsv); + return result; +} + +Color midiToColor(Note * note) { + Color result; + Vector3 hsv; // 3 floats: hue/color, saturation, value/brightness + + //hsv = (Vector3){intToHue(note->port, VIS_PORTS), 1.0f, (float)(note->velocity+40)/(float)167}; //Saturation is always 1, we tweak Value to never go into the black range. + float hue=ColorToHSV(programState.colors[note->port]).x; + hsv = (Vector3){hue, 1.0f, (float)(note->velocity+40)/(float)167}; //Saturation is always 1, we tweak Value to never go into the black range. + result = ColorFromHSV(hsv); + return result; +} + +void drawNoteRect(Note * note, int rotated, int square) { + if (note->active) { + //opacity is between 0.0f and 1.0f + int w,h; + + if (square==1) { + w = NOTE_SMALL_SIDE - NOTE_BORDER; + h = NOTE_SMALL_SIDE - NOTE_BORDER; + } + else { //Not Square + if (rotated==0) { + w = NOTE_SMALL_SIDE - NOTE_BORDER; + h = NOTE_LONG_SIDE - NOTE_BORDER; + } + else { + h = NOTE_SMALL_SIDE - NOTE_BORDER; + w = NOTE_LONG_SIDE - NOTE_BORDER; + } + } + + const Rectangle rec = (Rectangle){note->x, note->y, w,h}; + const Rectangle outer = (Rectangle){note->x-NOTE_BORDER/2, note->y-NOTE_BORDER/2, w+NOTE_BORDER, h+NOTE_BORDER}; + + Color bordercolor = Fade(BLACK, note->countdown); + Color color = Fade(programState.colors[note->port], note->countdown); + + //Drawing order is reverse Z-Order + DrawRectangleRounded(outer, 0.5, 8, bordercolor); //float roundness, int segments/smoothness, Color + DrawRectangleRounded(rec, 0.5, 8, color); + } +} + +bool portShouldDraw(int port) { + //Check various conditions if a port background, port name and pitch marker should be drawn + if ( programState.showPortBackgroundForUnconnected || ( programState.connectedPortNames[port] && programState.connectedPortNames[port][0] != '\0' )) { + return true; + } + else { + return false; + } + +} + +void drawJackPortName(const char * portname, int x, int y, int fontsize, Color color, bool vertical) { + + if (portname && portname[0] != '\0') { + + const char * finalPortName; + if (programState.includeClientInPortNameDisplay) { + finalPortName = portname; //TODO: Pretty Names don't contain the client name. Add it ourselves? + } + else { + if (strchr(portname, ':') == NULL ) //Pretty Names don't contain the client name. + { + finalPortName = portname; + } + else { + finalPortName = strchr(portname, ':')+1; + } + } //final port name is ready. + + + //Vertical Mode + //void DrawTextCodepoint(Font font, int codepoint, Vector2 position, float scale, Color tint); // Draw one character (codepoint) + if (vertical) { + //TODO: Wow, that is ugly! + int counter = 0; + char ch = finalPortName[counter]; + Font defaultFont = GetFontDefault(); + while (ch != '\0') { + DrawTextCodepoint(defaultFont, ch, (Vector2){ x, y+counter*(fontsize/1.5) }, 1.8f, color); + counter++; + ch = finalPortName[counter]; + } + } + else { + // Horizontal Mode + DrawText(finalPortName, x, y, fontsize, color); + } + } +} + +float calculateCountdown(float countdown, float ft) { + float bpmFactor; + + switch (programState.fadeOutMode) { + case 0: // framelegnth * user factor + if (countdown < 1.0f) { countdown -= (float)programState.fadeOutFactor * ft; } //note off has been triggered. Fade out. + if (countdown <= 0.0f) { countdown = 0; } // Is it now, or was already, below 0? + break; + + case 1: // bpm + bpmFactor = (float)(programState.bpm/40); + if (countdown < 1.0f) { countdown -= bpmFactor * ft; } //note off has been triggered. Fade out. + if (countdown <= 0.0f) { countdown = 0.0f; } // Is it now, or was already, below 0? + break; + + case 2: // no fadeout + if (countdown < 1.0f) { countdown = 0.0f; } // As soon as note off arrives + break; + + default: //just in case + countdown = 0.0f; + break; + } + + return countdown; +} + +void reduceCountdown(Note * nt, float ft) { + //Notes countdown is set to 0 (note-off), 1 (note-on) or 0.999 (note-off) by our jack midi client. + + float bpmFactor; + + if (nt->active == 1) { + switch (programState.fadeOutMode) { + case 0: // framelegnth * user factor + if (nt->countdown < 1.0f) { nt->countdown -= (float)programState.fadeOutFactor * ft; } //note off has been triggered. Fade out. + if (nt->countdown <= 0.0f) { nt->active = false; } // Is it now, or was already, below 0? + break; + + case 1: // bpm + bpmFactor = (float)(programState.bpm/40); + if (nt->countdown < 1.0f) { nt->countdown -= bpmFactor * ft; } //note off has been triggered. Fade out. + if (nt->countdown <= 0.0f) { nt->active = false; } // Is it now, or was already, below 0? + break; + + case 2: // no fadeout + if (nt->countdown < 1.0f) { nt->active = false; } // As soon as note off arrives + break; + + default: //just in case + nt->active = false; + break; + } + } +} diff --git a/drawhelper.h b/drawhelper.h new file mode 100644 index 0000000..61233f5 --- /dev/null +++ b/drawhelper.h @@ -0,0 +1,14 @@ +#ifndef DRAWHELPER_H +#define DRAWHELPER_H + +#include "constants.h" + +Color midiToColor(Note * note); +Color intToColor(int number, int maxnumber); +void drawNoteRect(Note * note, int rotated, int square); +void reduceCountdown(Note * nt, float ft); +float calculateCountdown(float countdown, float ft); +void drawJackPortName(const char * portname, int x, int y, int fontsize, Color color, bool vertical); +bool portShouldDraw(int port); + +#endif // not defined DRAWHELPER_H diff --git a/effect_starfield.c b/effect_starfield.c new file mode 100644 index 0000000..4bff4e1 --- /dev/null +++ b/effect_starfield.c @@ -0,0 +1,100 @@ +//Standard lib +#include + +//Third party +#include "raylib.h" + +//Our own files +#include "constants.h" +#include "programstate.h" +#include "effect_starfield.h" + +extern ProgramState programState; +static int screenWidth; +static int screenHeight; +static const int numberOfStars=540; + +static const int starLayers = 3; + +typedef struct { + int x; + int y; + int z; + Color color; + float rand; +} Star; + +static Star stars[540]; //1080 * 0.5 Not quite one star per line + +void reposition() { + //Recreate all stars and begin from blank. + //We want a certain star density, no matter the screen resolution + + screenWidth = GetScreenWidth(); + screenHeight = GetScreenHeight(); + Color color; + int rand; + int layer; + int partitionSize=(starLayers+1)*2 / 8; //8 partions + for (int i=0; ix -= (star->z * ft * bpmFactor * 3 * speedModifier); //... the mysterious number 3. + //wrap around + if (star->x <= 0) { + star->x += screenWidth; + star->y = GetRandomValue(0, screenHeight); + } + else if (star->x > screenWidth) { + star->x -= screenWidth; + star->y = GetRandomValue(0, screenHeight); + } + } + + //Wobble wobble + int rand = GetRandomValue(1, 200); + if (rand == 1) {star->y += 1;} + else if (rand == 2) {star->y -= 1;} + + DrawRectangle(star->x, star->y, size, size, Fade(star->color, opacity)); + } +} diff --git a/effect_starfield.h b/effect_starfield.h new file mode 100644 index 0000000..49d03fa --- /dev/null +++ b/effect_starfield.h @@ -0,0 +1,6 @@ +#ifndef effect_starfield_H +#define effect_starfield_H + +void effect_starfield(bool redrawNeeded, float opacity, int speedModifier, int size); + +#endif // not defined effect_starfield_H diff --git a/font.ttf b/font.ttf new file mode 100644 index 0000000000000000000000000000000000000000..9db958532c12ef7f4aa22fab57a0f71e82acdd38 GIT binary patch literal 714456 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

YoY{Tps(}N873!pmd$-^|tLKtcQ|SKo^_N|G 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 )r+_%USi1dhK+UkOZ?7=*O+WA-{?*j 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 // atoi for commandline argument char to int +#include +#include +#include + +//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 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", ¤tPaletteIndex, colorPaletteEditMode)) { colorPaletteEditMode = !colorPaletteEditMode; } + if (remember != currentPaletteIndex) { setColorPalette(currentPaletteIndex);} + //Draw last in this column + if (GuiDropdownBox((Rectangle){ columnX, 3*SPACING, 130, HEIGHT }, colorsPortsString, ¤tColorIndex, 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 // Required for: strcpy() + +//---------------------------------------------------------------------------------- +// Defines and Macros +//---------------------------------------------------------------------------------- +#define MAX_DIRECTORY_FILES 1024 +#define MAX_DIR_PATH_LENGTH 1024 + +//---------------------------------------------------------------------------------- +// Types and Structures Definition +//---------------------------------------------------------------------------------- + +#if defined(USE_CUSTOM_LISTVIEW_FILEINFO) +// Detailed file info type +typedef struct FileInfo { + const char *name; + int size; + int modTime; + int type; + int icon; +} FileInfo; +#else +// Filename only +typedef char *FileInfo; +#endif + +//---------------------------------------------------------------------------------- +// Global Variables Definition +//---------------------------------------------------------------------------------- +FileInfo *dirFilesIcon = NULL; + +//---------------------------------------------------------------------------------- +// Internal Module Functions Definition +//---------------------------------------------------------------------------------- +// Read all filenames from directory (supported file types) +static char **ReadDirectoryFiles(const char *dir, int *filesCount, char *filterExt); + +#if defined(USE_CUSTOM_LISTVIEW_FILEINFO) +// List View control for files info with extended parameters +static int GuiListViewFiles(Rectangle bounds, FileInfo *files, int count, int *focus, int *scrollIndex, int active); +#endif + +//---------------------------------------------------------------------------------- +// Module Functions Definition +//---------------------------------------------------------------------------------- +GuiFileDialogState InitGuiFileDialog(int width, int height, const char *initPath, bool active) +{ + GuiFileDialogState state = { 0 }; + + // Default dialog size is 440x310 + state.size.x = width == -1 ? 440 : width; + state.size.y = height == -1 ? 310 : height; + state.position = (Vector2){ GetScreenWidth()/2 - state.size.x/2, GetScreenHeight()/2 - state.size.y/2 }; + + state.fileDialogActive = active; + state.dirPathEditMode = false; + + state.filesListActive = -1; + state.prevFilesListActive = state.filesListActive; + state.filesListScrollIndex = 0; + + state.fileNameEditMode = false; + + state.SelectFilePressed = false; + state.CancelFilePressed = false; + + state.fileTypeActive = 0; + + strcpy(state.fileNameText, "\0"); + + // Custom variables initialization + if (initPath && DirectoryExists(initPath)) + { + strcpy(state.dirPathText, initPath); + } + else if (initPath && FileExists(initPath)) + { + strcpy(state.dirPathText, GetDirectoryPath(initPath)); + strcpy(state.fileNameText, GetFileName(initPath)); + } + else strcpy(state.dirPathText, GetWorkingDirectory()); + + strcpy(state.dirPathTextCopy, state.dirPathText); + strcpy(state.fileNameTextCopy, state.fileNameText); + + strcpy(state.filterExt, "all"); + + state.dirFilesCount = 0; + state.dirFiles = NULL; // NOTE: Loaded lazily on window active + + return state; +} + +// Read files in new path +static void FD_RELOAD_DIRPATH(GuiFileDialogState *state) +{ + for (int i = 0; i < state->dirFilesCount; i++) RL_FREE(state->dirFiles[i]); + RL_FREE(state->dirFiles); + + state->dirFiles = ReadDirectoryFiles(state->dirPathText, &state->dirFilesCount, state->filterExt); + state->itemFocused = 0; +} + +// Update and draw file dialog +void GuiFileDialog(GuiFileDialogState *state) +{ + if (state->fileDialogActive) + { + const int winWidth = state->size.x; + const int winHeight = state->size.y; + + // Load dirFilesIcon and state->dirFiles lazily on windows open + // NOTE: they are automatically unloaded at fileDialog closing + //------------------------------------------------------------------------------------ + if (dirFilesIcon == NULL) + { + dirFilesIcon = (FileInfo *)RL_MALLOC(MAX_DIRECTORY_FILES*sizeof(FileInfo)); // Max files to read + for (int i = 0; i < MAX_DIRECTORY_FILES; i++) dirFilesIcon[i] = (char *)calloc(MAX_DIR_PATH_LENGTH, 1); // Max file name length + } + + if (state->dirFiles == NULL) + { + state->dirFiles = ReadDirectoryFiles(state->dirPathText, &state->dirFilesCount, state->filterExt); + + for(int f = 0; f < state->dirFilesCount; f++) + { + if (strcmp(state->fileNameText, state->dirFiles[f]) == 0) + { + if (state->filesListActive != f) state->filesListScrollIndex = state->filesListActive = f; // make it active and visible only on first call + + break; + } + } + } + //------------------------------------------------------------------------------------ + + DrawRectangle(0, 0, GetScreenWidth(), GetScreenHeight(), Fade(GetColor(GuiGetStyle(DEFAULT, BACKGROUND_COLOR)), 0.85f)); + state->fileDialogActive = !GuiWindowBox((Rectangle){ state->position.x + 0, state->position.y + 0, winWidth, winHeight }, "#198#LuaJIT | Select File Dialog"); + + if (GuiButton((Rectangle){ state->position.x + winWidth - 50, state->position.y + 35, 40, 25 }, "< .."))// || IsKeyReleased(KEY_DPAD_Y)) + { + // Move dir path one level up + strcpy(state->dirPathText, GetPrevDirectoryPath(state->dirPathText)); + + // RL_FREE previous dirFiles (reloaded by ReadDirectoryFiles()) + FD_RELOAD_DIRPATH(state); + + state->filesListActive = -1; + strcpy(state->fileNameText, "\0"); + strcpy(state->fileNameTextCopy, state->fileNameText); + } + + if (GuiTextBox((Rectangle){ state->position.x + 10, state->position.y + 35, winWidth - 65, 25 }, state->dirPathText, 256, state->dirPathEditMode)) + { + if (state->dirPathEditMode) + { + // Verify if a valid path has been introduced + if (DirectoryExists(state->dirPathText)) + { + // RL_FREE previous dirFiles (reloaded by ReadDirectoryFiles()) + FD_RELOAD_DIRPATH(state); + + strcpy(state->dirPathTextCopy, state->dirPathText); + } + else strcpy(state->dirPathText, state->dirPathTextCopy); + } + + state->dirPathEditMode = !state->dirPathEditMode; + } + + int prevTextAlignment = GuiGetStyle(LISTVIEW, TEXT_ALIGNMENT); + int prevElementsHeight = GuiGetStyle(LISTVIEW, LIST_ITEMS_HEIGHT); + GuiSetStyle(LISTVIEW, TEXT_ALIGNMENT, GUI_TEXT_ALIGN_LEFT); + GuiSetStyle(LISTVIEW, LIST_ITEMS_HEIGHT, 24); + + // TODO: ListViewElements should be aligned left +# if defined(USE_CUSTOM_LISTVIEW_FILEINFO) + FileInfo fileInfo; + state->filesListActive = GuiListViewFiles((Rectangle){ state->position.x + 10, state->position.y + 70, winWidth - 20, winHeight - 135 }, fileInfo, state->dirFilesCount, &state->itemFocused, &state->filesListScrollIndex, state->filesListActive); +# else + state->filesListActive = GuiListViewEx((Rectangle){ state->position.x + 10, state->position.y + 70, winWidth - 20, winHeight - 135 }, (const char**)dirFilesIcon, state->dirFilesCount, &state->itemFocused, &state->filesListScrollIndex, state->filesListActive); +# endif + GuiSetStyle(LISTVIEW, TEXT_ALIGNMENT, prevTextAlignment); + GuiSetStyle(LISTVIEW, LIST_ITEMS_HEIGHT, prevElementsHeight); + + if ((state->filesListActive >= 0) && (state->filesListActive != state->prevFilesListActive)) + //&& (IsMouseButtonPressed(MOUSE_LEFT_BUTTON) || IsKeyPressed(KEY_ENTER) || IsKeyPressed(KEY_DPAD_A))) + { + strcpy(state->fileNameText, state->dirFiles[state->filesListActive]); + + if (DirectoryExists(TextFormat("%s/%s", state->dirPathText, state->fileNameText))) + { + if (TextIsEqual(state->fileNameText, "..")) strcpy(state->dirPathText, GetPrevDirectoryPath(state->dirPathText)); + else strcpy(state->dirPathText, TextFormat("%s/%s", strcmp(state->dirPathText, "/")==0 ? "" : state->dirPathText, state->fileNameText)); + + strcpy(state->dirPathTextCopy, state->dirPathText); + + // RL_FREE previous dirFiles (reloaded by ReadDirectoryFiles()) + FD_RELOAD_DIRPATH(state); + + strcpy(state->dirPathTextCopy, state->dirPathText); + + state->filesListActive = -1; + strcpy(state->fileNameText, "\0"); + strcpy(state->fileNameTextCopy, state->fileNameText); + } + + state->prevFilesListActive = state->filesListActive; + } + + GuiLabel((Rectangle){ state->position.x + 10, state->position.y + winHeight - 60, 68, 25 }, "File name:"); + + if (GuiTextBox((Rectangle){ state->position.x + 75, state->position.y + winHeight - 60, winWidth - 200, 25 }, state->fileNameText, 128, state->fileNameEditMode)) + { + if (*state->fileNameText) + { + // Verify if a valid filename has been introduced + if (FileExists(TextFormat("%s/%s", state->dirPathText, state->fileNameText))) + { + // Select filename from list view + for (int i = 0; i < state->dirFilesCount; i++) + { + if (TextIsEqual(state->fileNameText, state->dirFiles[i])) + { + state->filesListActive = i; + strcpy(state->fileNameTextCopy, state->fileNameText); + break; + } + } + } + else + { + strcpy(state->fileNameText, state->fileNameTextCopy); + } + } + + state->fileNameEditMode = !state->fileNameEditMode; + } + + state->fileTypeActive = GuiComboBox((Rectangle){ state->position.x + 75, state->position.y + winHeight - 30, winWidth - 200, 25 }, "All files", state->fileTypeActive); + GuiLabel((Rectangle){ state->position.x + 10, state->position.y + winHeight - 30, 68, 25 }, "File filter:"); + + state->SelectFilePressed = GuiButton((Rectangle){ state->position.x + winWidth - 120, state->position.y + winHeight - 60, 110, +#ifdef PLATFORM_DESKTOP + 25 +#else + 25+30 +#endif + }, "Select");// || IsKeyPressed(KEY_ENTER) || IsKeyPressed(KEY_DPAD_A); + + if (state->SelectFilePressed) state->fileDialogActive = false; + +#ifdef PLATFORM_DESKTOP + if (GuiButton((Rectangle){ state->position.x + winWidth - 120, state->position.y + winHeight - 30, 110, 25 }, "Quit")) state->fileDialogActive = false; +#endif + + // File dialog has been closed! + if (!state->fileDialogActive) + { + // RL_FREE dirFiles memory + for (int i = 0; i < state->dirFilesCount; i++) + { + RL_FREE(state->dirFiles[i]); + RL_FREE(dirFilesIcon[i]); + } + + RL_FREE(state->dirFiles); + RL_FREE(dirFilesIcon); + + dirFilesIcon = NULL; + state->dirFiles = NULL; + } + } +} + +// Read all filenames from directory (supported file types) +static inline int _file_comp(const char *d1, const char *d2, const char *dir) +{ + const bool b1 = DirectoryExists(TextFormat("%s/%s", dir, d1)); + const bool b2 = DirectoryExists(TextFormat("%s/%s", dir, d2)); + + if (b1 && !b2) return -1; + if (!b1 && b2) return 1; + + if (!FileExists(TextFormat("%s/%s", dir, d1))) return 1; + if (!FileExists(TextFormat("%s/%s", dir, d2))) return -1; + + return strcmp(d1, d2); +} +static char **ReadDirectoryFiles(const char *dir, int *filesCount, char *filterExt) +{ + int validFilesCount = 0; + char **validFiles = (char **)RL_MALLOC(MAX_DIRECTORY_FILES*sizeof(char *)); // Max files to read + for (int i = 0; i < MAX_DIRECTORY_FILES; i++) validFiles[i] = (char *)RL_MALLOC(MAX_DIR_PATH_LENGTH); // Max file name length + + int filterExtCount = 0; + const char **extensions = GuiTextSplit(filterExt, &filterExtCount, NULL); + bool filterExtensions = true; + + int dirFilesCount = 0; + char **files = GetDirectoryFiles(dir, &dirFilesCount); + + // Sort files and directories: dir by name + files by name + // https://en.wikibooks.org/wiki/Algorithm_Implementation/Sorting/Quicksort#C + if (dirFilesCount > 1) + { + const int MAX = 64; + unsigned int left = 0, stack[64], pos = 0, seed = rand(), len = dirFilesCount; + + for ( ; ; ) + { + for (; left+1 < len; len++) /* sort left to len-1 */ + { + if (pos == MAX) len = stack[pos = 0]; /* stack overflow, reset */ + char *pivot = files[left+seed%(len-left)]; /* pick random pivot */ + seed = seed*69069+1; /* next pseudorandom number */ + stack[pos++] = len; /* sort right part later */ + + for (unsigned int right = left-1; ; ) /* inner loop: partitioning */ + { + while (_file_comp(files[++right], pivot, dir) < 0);/* look for greater element */ + while (_file_comp(pivot, files[--len], dir) < 0); /* look for smaller element */ + if (right >= len) break; /* partition point found? */ + char *temp = files[right]; + files[right] = files[len]; /* the only swap */ + files[len] = temp; + } /* partitioned, continue left part */ + } + + if (pos == 0) break; /* stack empty? */ + left = len; /* left to right is sorted */ + len = stack[--pos]; /* get next range to sort */ + } + } + + if (TextIsEqual(extensions[0], "all")) filterExtensions = false; + + for (int i = 0; (i < dirFilesCount) && (validFilesCount < MAX_DIRECTORY_FILES); i++) + { + if (TextIsEqual(files[i], ".")) continue; + + if (!filterExtensions) + { + strncpy(validFiles[validFilesCount], files[i], MAX_DIR_PATH_LENGTH); + + // Only filter files by extensions, directories should be available + if (DirectoryExists(TextFormat("%s/%s", dir, files[i]))) strcpy(dirFilesIcon[validFilesCount], TextFormat("%s", files[i])); + else + { + // TODO: Assign custom filetype icons depending on file extension (image, audio, text, video, models...) + + if (IsFileExtension(files[i], ".png")) strcpy(dirFilesIcon[validFilesCount], TextFormat("%s", files[i])); + else strcpy(dirFilesIcon[validFilesCount], TextFormat("%s", files[i])); + } + + validFilesCount++; + } + else + { + for (int j = 0; j < filterExtCount; j++) + { + // Check file type extensions supported + // NOTE: We just store valid files list + if (IsFileExtension(files[i], extensions[j])) + { + // TODO: Assign custom filetype icons depending on file extension (image, audio, text, video, models...) + + if (IsFileExtension(files[i], ".png")) strcpy(dirFilesIcon[validFilesCount], TextFormat("%s", files[i])); + else strcpy(dirFilesIcon[validFilesCount], TextFormat("%s", files[i])); + + validFilesCount++; + } + } + } + } + + ClearDirectoryFiles(); + + *filesCount = validFilesCount; + return validFiles; +} + +#if defined(USE_CUSTOM_LISTVIEW_FILEINFO) +// List View control for files info with extended parameters +static int GuiListViewFiles(Rectangle bounds, FileInfo *files, int count, int *focus, int *scrollIndex, int active) +{ + GuiControlState state = guiState; + int itemFocused = (focus == NULL)? -1 : *focus; + int itemSelected = active; + + // Check if we need a scroll bar + bool useScrollBar = false; + if ((GuiGetStyle(LISTVIEW, LIST_ITEMS_HEIGHT) + GuiGetStyle(LISTVIEW, LIST_ITEMS_PADDING))*count > bounds.height) useScrollBar = true; + + // Define base item rectangle [0] + Rectangle itemBounds = { 0 }; + itemBounds.x = bounds.x + GuiGetStyle(LISTVIEW, LIST_ITEMS_PADDING); + itemBounds.y = bounds.y + GuiGetStyle(LISTVIEW, LIST_ITEMS_PADDING) + GuiGetStyle(DEFAULT, BORDER_WIDTH); + itemBounds.width = bounds.width - 2*GuiGetStyle(LISTVIEW, LIST_ITEMS_PADDING) - GuiGetStyle(DEFAULT, BORDER_WIDTH); + itemBounds.height = GuiGetStyle(LISTVIEW, LIST_ITEMS_HEIGHT); + if (useScrollBar) itemBounds.width -= GuiGetStyle(LISTVIEW, SCROLLBAR_WIDTH); + + // Get items on the list + int visibleItems = bounds.height/(GuiGetStyle(LISTVIEW, LIST_ITEMS_HEIGHT) + GuiGetStyle(LISTVIEW, LIST_ITEMS_PADDING)); + if (visibleItems > count) visibleItems = count; + + int startIndex = (scrollIndex == NULL)? 0 : *scrollIndex; + if ((startIndex < 0) || (startIndex > (count - visibleItems))) startIndex = 0; + int endIndex = startIndex + visibleItems; + + // Update control + //-------------------------------------------------------------------- + if ((state != GUI_STATE_DISABLED) && !guiLocked) + { + Vector2 mousePoint = GetMousePosition(); + + // Check mouse inside list view + if (CheckCollisionPointRec(mousePoint, bounds)) + { + state = GUI_STATE_FOCUSED; + + // Check focused and selected item + for (int i = 0; i < visibleItems; i++) + { + if (CheckCollisionPointRec(mousePoint, itemBounds)) + { + itemFocused = startIndex + i; + if (IsMouseButtonPressed(MOUSE_LEFT_BUTTON)) itemSelected = startIndex + i; + break; + } + + // Update item rectangle y position for next item + itemBounds.y += (GuiGetStyle(LISTVIEW, LIST_ITEMS_HEIGHT) + GuiGetStyle(LISTVIEW, LIST_ITEMS_PADDING)); + } + + if (useScrollBar) + { + int wheelMove = GetMouseWheelMove(); + startIndex -= wheelMove; + + if (startIndex < 0) startIndex = 0; + else if (startIndex > (count - visibleItems)) startIndex = count - visibleItems; + + endIndex = startIndex + visibleItems; + if (endIndex > count) endIndex = count; + } + } + else itemFocused = -1; + + // Reset item rectangle y to [0] + itemBounds.y = bounds.y + GuiGetStyle(LISTVIEW, LIST_ITEMS_PADDING) + GuiGetStyle(DEFAULT, BORDER_WIDTH); + } + //-------------------------------------------------------------------- + + // Draw control + //-------------------------------------------------------------------- + DrawRectangleRec(bounds, GetColor(GuiGetStyle(DEFAULT, BACKGROUND_COLOR))); // Draw background + DrawRectangleLinesEx(bounds, GuiGetStyle(DEFAULT, BORDER_WIDTH), Fade(GetColor(GuiGetStyle(LISTVIEW, BORDER + state*3)), guiAlpha)); + + // TODO: Draw list view header with file sections: icon+name | size | type | modTime + + // Draw visible items + for (int i = 0; i < visibleItems; i++) + { + if (state == GUI_STATE_DISABLED) + { + if ((startIndex + i) == itemSelected) + { + DrawRectangleRec(itemBounds, Fade(GetColor(GuiGetStyle(LISTVIEW, BASE_COLOR_DISABLED)), guiAlpha)); + DrawRectangleLinesEx(itemBounds, GuiGetStyle(LISTVIEW, BORDER_WIDTH), Fade(GetColor(GuiGetStyle(LISTVIEW, BORDER_COLOR_DISABLED)), guiAlpha)); + } + + // TODO: Draw full file info line: icon+name | size | type | modTime + + GuiDrawText(files[startIndex + i].name, GetTextBounds(DEFAULT, itemBounds), GuiGetStyle(LISTVIEW, TEXT_ALIGNMENT), Fade(GetColor(GuiGetStyle(LISTVIEW, TEXT_COLOR_DISABLED)), guiAlpha)); + } + else + { + if ((startIndex + i) == itemSelected) + { + // Draw item selected + DrawRectangleRec(itemBounds, Fade(GetColor(GuiGetStyle(LISTVIEW, BASE_COLOR_PRESSED)), guiAlpha)); + DrawRectangleLinesEx(itemBounds, GuiGetStyle(LISTVIEW, BORDER_WIDTH), Fade(GetColor(GuiGetStyle(LISTVIEW, BORDER_COLOR_PRESSED)), guiAlpha)); + + GuiDrawText(files[startIndex + i].name, GetTextBounds(DEFAULT, itemBounds), GuiGetStyle(LISTVIEW, TEXT_ALIGNMENT), Fade(GetColor(GuiGetStyle(LISTVIEW, TEXT_COLOR_PRESSED)), guiAlpha)); + } + else if ((startIndex + i) == itemFocused) + { + // Draw item focused + DrawRectangleRec(itemBounds, Fade(GetColor(GuiGetStyle(LISTVIEW, BASE_COLOR_FOCUSED)), guiAlpha)); + DrawRectangleLinesEx(itemBounds, GuiGetStyle(LISTVIEW, BORDER_WIDTH), Fade(GetColor(GuiGetStyle(LISTVIEW, BORDER_COLOR_FOCUSED)), guiAlpha)); + + GuiDrawText(files[startIndex + i].name, GetTextBounds(DEFAULT, itemBounds), GuiGetStyle(LISTVIEW, TEXT_ALIGNMENT), Fade(GetColor(GuiGetStyle(LISTVIEW, TEXT_COLOR_FOCUSED)), guiAlpha)); + } + else + { + // Draw item normal + GuiDrawText(files[startIndex + i].name, GetTextBounds(DEFAULT, itemBounds), GuiGetStyle(LISTVIEW, TEXT_ALIGNMENT), Fade(GetColor(GuiGetStyle(LISTVIEW, TEXT_COLOR_NORMAL)), guiAlpha)); + } + } + + // Update item rectangle y position for next item + itemBounds.y += (GuiGetStyle(LISTVIEW, LIST_ITEMS_HEIGHT) + GuiGetStyle(LISTVIEW, LIST_ITEMS_PADDING)); + } + + if (useScrollBar) + { + Rectangle scrollBarBounds = { + bounds.x + bounds.width - GuiGetStyle(LISTVIEW, BORDER_WIDTH) - GuiGetStyle(LISTVIEW, SCROLLBAR_WIDTH), + bounds.y + GuiGetStyle(LISTVIEW, BORDER_WIDTH), (float)GuiGetStyle(LISTVIEW, SCROLLBAR_WIDTH), + bounds.height - 2*GuiGetStyle(DEFAULT, BORDER_WIDTH) + }; + + // Calculate percentage of visible items and apply same percentage to scrollbar + float percentVisible = (float)(endIndex - startIndex)/count; + float sliderSize = bounds.height*percentVisible; + + int prevSliderSize = GuiGetStyle(SCROLLBAR, SLIDER_WIDTH); // Save default slider size + int prevScrollSpeed = GuiGetStyle(SCROLLBAR, SCROLL_SPEED); // Save default scroll speed + GuiSetStyle(SCROLLBAR, SLIDER_WIDTH, sliderSize); // Change slider size + GuiSetStyle(SCROLLBAR, SCROLL_SPEED, count - visibleItems); // Change scroll speed + + startIndex = GuiScrollBar(scrollBarBounds, startIndex, 0, count - visibleItems); + + GuiSetStyle(SCROLLBAR, SCROLL_SPEED, prevScrollSpeed); // Reset scroll speed to default + GuiSetStyle(SCROLLBAR, SLIDER_WIDTH, prevSliderSize); // Reset slider size to default + } + //-------------------------------------------------------------------- + + if (focus != NULL) *focus = itemFocused; + if (scrollIndex != NULL) *scrollIndex = startIndex; + + return itemSelected; +} +#endif // USE_CUSTOM_LISTVIEW_FILEINFO + +#endif // GUI_FILE_DIALOG_IMPLEMENTATION diff --git a/jRead.c b/jRead.c new file mode 100644 index 0000000..5bdd5e5 --- /dev/null +++ b/jRead.c @@ -0,0 +1,789 @@ +//Author: Tony Wilk +//Source: https://www.codeproject.com/Articles/885389/jRead-An-in-place-JSON-Element-Reader +//LICENSE: The Code Project Open License (CPOL) 1.02 +//see provided file ICENSE_jReadJWrite.html or https://www.codeproject.com/info/cpol10.aspx + +// jRead.cpp +// Version 1v6 +// +// jRead - an in-place JSON element reader +// ======================================= +// +// Instead of parsing JSON into some structure, this maintains the input JSON as unaltered text +// and allows queries to be made on it directly. +// +// e.g. with the simple JSON: +// { +// "astring":"This is a string", +// "anumber":42, +// "myarray":[ "one", 2, {"description":"element 3"}, null ], +// "yesno":true, +// "HowMany":"1234", +// "foo":null +// } +// +// calling: +// jRead( json, "{'myarray'[0", &jElem ); +// +// would return: +// jElem.dataType= JREAD_STRING; +// jElem.elements= 1 +// jElem.bytelen= 3 +// jElem.pValue -> "one" +// +// or you could call the helper functions: +// jRead_string( json, "{'astring'", destString, MAXLEN ); +// jRead_int( json, "{'anumber'", &myint ); +// jRead_string( json, "{'myarray'[3", destString, MAXLEN ); +// etc. +// +// Note that the helper functions do type coersion and always return a value +// (on error an empty string is returned or value of zero etc.) +// +// The query string simply defines the route to the required data item +// as an arbitary list of object or array specifiers: +// object element= "{'keyname'" +// array element= "[INDEX" +// +// The jRead() function fills a jReadElement structure to describe the located element +// this can be used to locate any element, not just terminal values +// e.g. +// jRead( json, "{'myarray'", &jElem ); +// +// in this case jElem would contain: +// jElem.dataType= JSON_ARRAY +// jElem.elements= 4 +// jElem.bytelen= 46 +// jElem.pValue -> [ "one", 2, {"descripton":"element 3"}, null ] ... +// +// allowing jRead to be called again on the array: +// e.g. +// jRead( jElem.pValue, "[3", &jElem ); // get 4th element - the null value +// +// .oO! see main.c runExamples() for a whole bunch of examples !Oo. +// ------------------------------------------------------- +// +// Note that jRead never modifies the source JSON and does not allocate any memory. +// i.e. elements are returned as pointer and length into the source text. +// +// Functions +// ========= +// Main JSON reader: +// int jRead( char * JsonSource, char *query, jReadElement &pResult ); +// +// Extended function using query parameters for indexing: +// int jRead( char * JsonSource, char *query, jReadElement &pResult, int *queryParams ); +// +// Function to step thru JSON arrays instead of indexing: +// char *jReadArrayStep( char *pJsonArray, struct jReadElement *pResult ); +// +// Optional Helper functions: +// long jRead_long( char *pJson, char *pQuery ); +// int jRead_int( char *pJson, char *pQuery ); +// double jRead_double( char *pJson, char *pQuery ); +// int jRead_string( char *pJson, char *pQuery, char *pDest, int destlen ); +// +// Optional String output Functions +// char * jReadTypeToString( int dataType ); // string describes dataType +// char * jReadErrorToString( int error ); // string descibes error code +// +// *NEW* in 1v2 +// - "{NUMBER" returns the "key" value at that index within an object +// - jReadParam() adds queryParams which can be used as indexes into arrays (or into +// objects to return key values) by specifying '*' in the query string +// e.g. jReadParam( pJson, "[*", &result, &index ) +// *NEW in 1v4 +// - fixed a couple of error return values +// - added #define JREAD_DOUBLE_QUOTE_IN_QUERY +// *NEW* in 1v5 (11mar2015) +// - fixed null ptr if '[*' used when null param passed +// *NEW* in 1v6 (24sep2016) +// - fixed handling of empty arrays and objects +// +// TonyWilk, 24sep2016 +// mail at tonywilk . co .uk +// +// License: "Free as in You Owe Me a Beer" +// - actually, since some people really worry about licenses, you are free to apply +// whatever licence you want. +// +// Note: jRead_atol() and jRead_atof() are modified from original routines +// fast_atol() and fast_atof() 09-May-2009 Tom Van Baak (tvb) www.LeapSecond.com +// +// You may want to replace the use of jRead_atol() and jRead_atof() in helper functions +// of your own. Especially note that my atof does not handle exponents. +// +// +#include + +#include "jRead.h" + +// By default we use single quote in query strings so it's a lot easier +// to type in code i.e. "{'key'" instead of "{\"key\"" +// +#ifdef JREAD_DOUBLE_QUOTE_IN_QUERY +#define QUERY_QUOTE '\"' +#else +#define QUERY_QUOTE '\'' +#endif + +//------------------------------------------------------ +// Internal Functions + +char * jReadSkipWhitespace( char *sp ); +char * jReadFindTok( char *sp, int *tokType ); +char * jReadGetString( char *pJson, struct jReadElement *pElem, char quote ); +int jReadTextLen( char *pJson ); +int jReadStrcmp( struct jReadElement *j1, struct jReadElement *j2 ); +char * jReadCountObject( char *pJson, struct jReadElement *pResult, int keyIndex ); +char * jReadCountArray( char *pJson, struct jReadElement *pResult ); +char * jRead_atoi( char *p, unsigned int *result ); +char * jRead_atol( char *p, long *result ); +char * jRead_atof( char *p, double *result); + +//======================================================= + +char *jReadSkipWhitespace( char *sp ) +{ + while( (*sp != '\0') && (*sp <= ' ') ) + sp++; + return sp; +}; + + +// Find start of a token +// - returns pointer to start of next token or element +// returns type via tokType +// +char *jReadFindTok( char *sp, int *tokType ) +{ + char c; + sp= jReadSkipWhitespace(sp); + c= *sp; + if( c == '\0' ) *tokType= JREAD_EOL; + else if((c == '"') || (c == QUERY_QUOTE))*tokType= JREAD_STRING; + else if((c >= '0') && (c <= '9')) *tokType= JREAD_NUMBER; + else if( c == '-') *tokType= JREAD_NUMBER; + else if( c == '{') *tokType= JREAD_OBJECT; + else if( c == '[') *tokType= JREAD_ARRAY; + else if( c == '}') *tokType= JREAD_EOBJECT; + else if( c == ']') *tokType= JREAD_EARRAY; + else if((c == 't') || (c == 'f')) *tokType= JREAD_BOOL; + else if( c == 'n') *tokType= JREAD_NULL; + else if( c == ':') *tokType= JREAD_COLON; + else if( c == ',') *tokType= JREAD_COMMA; + else if( c == '*') *tokType= JREAD_QPARAM; + else *tokType= JREAD_ERROR; + return sp; +}; + +// jReadGetString +// - assumes next element is "string" which may include "\" sequences +// - returns pointer to -------------^ +// - pElem contains result ( JREAD_STRING, length, pointer to string) +// - pass quote = '"' for Json, quote = '\'' for query scanning +// +// returns: pointer into pJson after the string (char after the " terminator) +// pElem contains pointer and length of string (or dataType=JREAD_ERROR) +// +char * jReadGetString( char *pJson, struct jReadElement *pElem, char quote ) +{ + short skipch; + pElem->dataType= JREAD_ERROR; + pElem->elements= 1; + pElem->bytelen= 0; + pJson= jReadSkipWhitespace( pJson ); + if( *pJson == quote ) + { + pJson++; + pElem->pValue= pJson; // -> start of actual string + pElem->bytelen=0; + skipch= 0; + while( *pJson != '\0' ) + { + if( skipch ) + skipch= 0; + else if( *pJson == '\\' ) // "\" sequence + skipch= 1; + else if( *pJson == quote ) + { + pElem->dataType= JREAD_STRING; + pJson++; + break; + } + pElem->bytelen++; + pJson++; + }; + }; + return pJson; +}; + +// jReadTextLen +// - used to identify length of element text +// - returns no. of chars from pJson upto a terminator +// - terminators: ' ' , } ] +// +int jReadTextLen( char *pJson ) +{ + int len= 0; + while( (*pJson > ' ' ) && // any ctrl char incl '\0' + (*pJson != ',' ) && + (*pJson != '}' ) && + (*pJson != ']' ) ) + { + len++; + pJson++; + } + return len; +} + +// compare two json elements +// returns: 0 if they are identical strings, else 1 +// +int jReadStrcmp( struct jReadElement *j1, struct jReadElement *j2 ) +{ + int i; + if( (j1->dataType != JREAD_STRING) || + (j2->dataType != JREAD_STRING) || + (j1->bytelen != j2->bytelen ) ) + return 1; + + for( i=0; i< j1->bytelen; i++ ) + if( ((char *)(j1->pValue))[i] != ((char *)(j2->pValue))[i] ) + return 1; + return 0; +} + +// read unsigned int from string +char * jRead_atoi( char *p, unsigned int *result ) +{ + unsigned int x = 0; + while (*p >= '0' && *p <= '9') { + x = (x*10) + (*p - '0'); + ++p; + } + *result= x; + return p; +} + +// read long int from string +// +char * jRead_atol( char *p, long *result ) +{ + long x = 0; + int neg = 0; + if (*p == '-') { + neg = 1; + ++p; + } + while (*p >= '0' && *p <= '9') { + x = (x*10) + (*p - '0'); + ++p; + } + if (neg) { + x = -x; + } + *result= x; + return p; +} + + +#define valid_digit(c) ((c) >= '0' && (c) <= '9') + +// read double from string +// *CAUTION* does not handle exponents +// +// +char * jRead_atof( char *p, double *result) +{ + double sign, value; + + // Get sign, if any. + sign = 1.0; + if (*p == '-') { + sign = -1.0; + p += 1; + + } else if (*p == '+') { + p += 1; + } + + // Get digits before decimal point or exponent, if any. + for (value = 0.0; valid_digit(*p); p += 1) { + value = value * 10.0 + (*p - '0'); + } + + // Get digits after decimal point, if any. + if (*p == '.') { + double pow10 = 10.0; + p += 1; + while (valid_digit(*p)) { + value += (*p - '0') / pow10; + pow10 *= 10.0; + p += 1; + } + } + *result= sign * value; + return p; +} + +// read element into destination buffer and add '\0' terminator +// - always copies element irrespective of dataType (unless it's an error) +// - destBuffer is always '\0'-terminated (even on zero lenght returns) +// - returns pointer to destBuffer +// +char *jRead_strcpy( char *destBuffer, int destLength, struct jReadElement *pElement ) +{ + int i; + int len= pElement->bytelen; + char *pdest= destBuffer; + char *psrc= (char *)pElement->pValue; + if( pElement->error == 0 ) + { + if( len >= destLength ) + len= destLength; + for( i=0; i "{... " +// - used to skip unwanted values which are objects +// - keyIndex normally passed as -1 unless we're looking for the nth "key" value +// in which case keyIndex is the index of the key we want +// +char * jReadCountObject( char *pJson, struct jReadElement *pResult, int keyIndex ) +{ + struct jReadElement jElement; + int jTok; + char *sp; + pResult->dataType= JREAD_OBJECT; + pResult->error= 0; + pResult->elements= 0; + pResult->pValue= pJson; + sp= jReadFindTok( pJson+1, &jTok ); // check for empty object + if( jTok == JREAD_EOBJECT ) + { + pJson= sp+1; + }else + { + while( 1 ) + { + pJson= jReadGetString( ++pJson, &jElement, '\"' ); + if( jElement.dataType != JREAD_STRING ) + { + pResult->error= 3; // Expected "key" + break; + } + if( pResult->elements == keyIndex ) // if passed keyIndex + { + *pResult= jElement; // we return "key" at this index + pResult->dataType= JREAD_KEY; + return pJson; + } + pJson= jReadFindTok( pJson, &jTok ); + if( jTok != JREAD_COLON ) + { + pResult->error= 4; // Expected ":" + break; + } + pJson= jRead( ++pJson, "", &jElement ); + if( pResult->error ) + break; + pJson= jReadFindTok( pJson, &jTok ); + pResult->elements++; + if( jTok == JREAD_EOBJECT ) + { + pJson++; + break; + } + if( jTok != JREAD_COMMA ) + { + pResult->error= 6; // Expected "," in object + break; + } + } + } + if( keyIndex >= 0 ) + { + // we wanted a "key" value - that we didn't find + pResult->dataType= JREAD_ERROR; + pResult->error= 11; // Object key not found (bad index) + }else{ + pResult->bytelen= pJson - (char *)pResult->pValue; + } + return pJson; +} + + + +// jReadCountArray +// - used when query ends at an array, we want to return the array length +// - on entry pJson -> "[... " +// - used to skip unwanted values which are arrays +// +char * jReadCountArray( char *pJson, struct jReadElement *pResult ) +{ + struct jReadElement jElement; + int jTok; + char *sp; + pResult->dataType= JREAD_ARRAY; + pResult->error= 0; + pResult->elements= 0; + pResult->pValue= pJson; + sp= jReadFindTok( pJson+1, &jTok ); // check for empty array + if( jTok == JREAD_EARRAY ) + { + pJson= sp+1; + }else + { + while( 1 ) + { + pJson= jRead( ++pJson, "", &jElement ); // array value + if( pResult->error ) + break; + pJson= jReadFindTok( pJson, &jTok ); // , or ] + pResult->elements++; + if( jTok == JREAD_EARRAY ) + { + pJson++; + break; + } + if( jTok != JREAD_COMMA ) + { + pResult->error= 9; // Expected "," in array + break; + } + } + } + pResult->bytelen= pJson - (char *)pResult->pValue; + return pJson; +} + +// jReadArrayStep() +// - reads one value from an array +// - assumes pJsonArray points at the start of an array or array element +// +char *jReadArrayStep( char *pJsonArray, struct jReadElement *pResult ) +{ + int jTok; + + pJsonArray= jReadFindTok( pJsonArray, &jTok ); + switch( jTok ) + { + case JREAD_ARRAY: // start of array + case JREAD_COMMA: // element separator + return jRead( ++pJsonArray, "", pResult ); + + case JREAD_EARRAY: // end of array + pResult->error= 13; // End of array found + break; + default: // some other error + pResult->error= 9; // expected comma in array + break; + } + pResult->dataType= JREAD_ERROR; + return pJsonArray; +} + + +// jRead +// - reads a complete JSON +// - matches pQuery against pJson, results in pResult +// returns: pointer into pJson +// +// Note: is recursive +// +char * jRead( char *pJson, char *pQuery, struct jReadElement *pResult ) +{ + return jReadParam( pJson, pQuery, pResult, NULL ); +} + +char * jReadParam( char *pJson, char *pQuery, struct jReadElement *pResult, int *queryParams ) +{ + int qTok, jTok, bytelen; + unsigned int index, count; + struct jReadElement qElement, jElement; + + pJson= jReadFindTok( pJson, &jTok ); + pQuery= jReadFindTok( pQuery, &qTok ); + + pResult->dataType= jTok; + pResult->bytelen= pResult->elements= pResult->error= 0; + pResult->pValue= pJson; + + if( (qTok != JREAD_EOL) && (qTok != jTok) ) + { + pResult->error= 1; // JSON does not match Query + return pJson; + } + + switch( jTok ) + { + case JREAD_ERROR: // general error, eof etc. + pResult->error= 2; // Error reading JSON value + break; + + case JREAD_OBJECT: // "{" + if( qTok == JREAD_EOL ) + return jReadCountObject( pJson, pResult, -1 ); // return length of object + + pQuery= jReadFindTok( ++pQuery, &qTok ); // "('key'...", "{NUMBER", "{*" or EOL + if( qTok != JREAD_STRING ) + { + index= 0; + switch( qTok ) + { + case JREAD_NUMBER: + pQuery= jRead_atoi( (char *)pQuery, &index ); // index value + break; + case JREAD_QPARAM: + pQuery++; + index= (queryParams != NULL) ? *queryParams++ : 0; // substitute parameter + break; + default: + pResult->error= 12; // Bad Object key + return pJson; + } + return jReadCountObject( pJson, pResult, index ); + } + + pQuery= jReadGetString( pQuery, &qElement, QUERY_QUOTE ); // qElement = query 'key' + // + // read : , ... } + // loop 'til key matched + // + while( 1 ) + { + pJson= jReadGetString( ++pJson, &jElement, '\"' ); + if( jElement.dataType != JREAD_STRING ) + { + pResult->error= 3; // Expected "key" + break; + } + pJson= jReadFindTok( pJson, &jTok ); + if( jTok != JREAD_COLON ) + { + pResult->error= 4; // Expected ":" + break; + } + // compare object keys + if( jReadStrcmp( &qElement, &jElement ) == 0 ) + { + // found object key + return jReadParam( ++pJson, pQuery, pResult, queryParams ); + } + // no key match... skip this value + pJson= jRead( ++pJson, "", pResult ); + pJson= jReadFindTok( pJson, &jTok ); + if( jTok == JREAD_EOBJECT ) + { + pResult->error= 5; // Object key not found + break; + } + if( jTok != JREAD_COMMA ) + { + pResult->error= 6; // Expected "," in object + break; + } + } + break; + case JREAD_ARRAY: // "[NUMBER" or "[*" + // + // read index, skip values 'til index + // + if( qTok == JREAD_EOL ) + return jReadCountArray( pJson, pResult ); // return length of object + + index= 0; + pQuery= jReadFindTok( ++pQuery, &qTok ); // "[NUMBER" or "[*" + if( qTok == JREAD_NUMBER ) + { + pQuery= jRead_atoi( pQuery, &index ); // get array index + }else if( qTok == JREAD_QPARAM ) + { + pQuery++; + index= (queryParams != NULL) ? *queryParams++ : 0; // substitute parameter + } + + count=0; + while( 1 ) + { + if( count == index ) + return jReadParam( ++pJson, pQuery, pResult, queryParams ); // return value at index + // not this index... skip this value + pJson= jRead( ++pJson, "", &jElement ); + if( pResult->error ) + break; + count++; + pJson= jReadFindTok( pJson, &jTok ); // , or ] + if( jTok == JREAD_EARRAY ) + { + pResult->error= 10; // Array element not found (bad index) + break; + } + if( jTok != JREAD_COMMA ) + { + pResult->error= 9; // Expected "," in array + break; + } + } + break; + case JREAD_STRING: // "string" + pJson= jReadGetString( pJson, pResult, '\"' ); + break; + case JREAD_NUMBER: // number (may be -ve) int or float + case JREAD_BOOL: // true or false + case JREAD_NULL: // null + bytelen= jReadTextLen( pJson ); + pResult->dataType= jTok; + pResult->bytelen= bytelen; + pResult->pValue= pJson; + pResult->elements= 1; + pJson += bytelen; + break; + default: + pResult->error= 8; // unexpected character (in pResult->dataType) + } + // We get here on a 'terminal value' + // - make sure the query string is empty also + pQuery= jReadFindTok( pQuery, &qTok ); + if( !pResult->error && (qTok != JREAD_EOL) ) + pResult->error= 7; // terminal value found before end of query + if( pResult->error ) + { + pResult->dataType= JREAD_ERROR; + pResult->elements= pResult->bytelen= 0; + pResult->pValue= pJson; // return pointer into JSON at error point + } + return pJson; +} + + +//-------------------------------------------------------------------- +// Optional helper functions +// - simple routines to extract values from JSON +// - does coercion of types where possible +// - always returns a value (e.g. 0 or "" on error) +// +// Note: by default, pass NULL for queryParams +// unless you are using '*' in the query for indexing +// + +// jRead_long +// - reads signed long value from JSON +// - returns number from NUMBER or STRING elements (if possible) +// returns 1 or 0 from BOOL elements +// otherwise returns 0 +// +long jRead_long( char *pJson, char *pQuery, int *queryParams ) +{ + struct jReadElement elem; + long result; + jReadParam( pJson, pQuery, &elem, queryParams ); + if( (elem.dataType == JREAD_ERROR) || (elem.dataType == JREAD_NULL)) + return 0; + if( elem.dataType == JREAD_BOOL ) + return *((char *)elem.pValue)=='t' ? 1 : 0; + + jRead_atol( (char *)elem.pValue, &result ); + return result; +} + +int jRead_int( char *pJson, char *pQuery, int *queryParams ) +{ + return (int)jRead_long( pJson, pQuery, queryParams ); +} + +// jRead_double +// - returns double from JSON +// - returns number from NUMBER or STRING elements +// otherwise returns 0.0 +// +double jRead_double( char *pJson, char *pQuery, int *queryParams ) +{ + struct jReadElement elem; + double result; + jReadParam( pJson, pQuery, &elem, queryParams ); + if( elem.dataType == JREAD_ERROR ) + return 0.0; + jRead_atof( (char *)elem.pValue, &result ); + return result; +} + +// jRead_string +// Copy string to pDest and '\0'-terminate it (upto destlen total bytes) +// returns: character length of string (excluding '\0' terminator) +// +// Note: any element can be returned as a string +// +int jRead_string( char *pJson, char *pQuery, char *pDest, int destlen, int *queryParams ) +{ + struct jReadElement elem; + int i; + + *pDest= '\0'; + jReadParam( pJson, pQuery, &elem, queryParams ); + if( elem.dataType == JREAD_ERROR ) + return 0; + + for( i=0; (i=0 ) && (error <= 14)) + return jReadErrorStrings[ error ]; + return "Unknown error"; +}; + +// end of jRead.c diff --git a/jRead.h b/jRead.h new file mode 100644 index 0000000..08e728c --- /dev/null +++ b/jRead.h @@ -0,0 +1,134 @@ +//Author: Tony Wilk +//Source: https://www.codeproject.com/Articles/885389/jRead-An-in-place-JSON-Element-Reader +//LICENSE: The Code Project Open License (CPOL) 1.02 +//see provided file ICENSE_jReadJWrite.html or https://www.codeproject.com/info/cpol10.aspx + + +// jRead.h +// +// see jRead.c for more information +// + +// uncomment this if you really want to use double quotes in query strings instead of ' +//#define JREAD_DOUBLE_QUOTE_IN_QUERY + +// +// return dataTypes: +#define JREAD_ERROR 0 // general error, eof etc. +#define JREAD_OBJECT 1 // "{" +#define JREAD_ARRAY 2 // "[" +#define JREAD_STRING 3 // "string" +#define JREAD_NUMBER 4 // number (may be -ve) int or float +#define JREAD_BOOL 5 // true or false +#define JREAD_NULL 6 // null +#define JREAD_KEY 7 // object "key" +// internal values: +#define JREAD_COLON 8 // ":" +#define JREAD_EOL 9 // end of input string (ptr at '\0') +#define JREAD_COMMA 10 // "," +#define JREAD_EOBJECT 11 // "}" +#define JREAD_EARRAY 12 // "]" +#define JREAD_QPARAM 13 // "*" query string parameter + +//------------------------------------------------------ +// jReadElement +// - structure to return JSON elements +// - error=0 for valid returns +// +// *NOTES* +// the returned pValue pointer points into the passed JSON +// string returns are not '\0' terminated. +// bytelen specifies the length of the returned data pointed to by pValue +// +struct jReadElement{ + int dataType; // one of JREAD_... + int elements; // number of elements (e.g. elements in array or object) + int bytelen; // byte length of element (e.g. length of string, array text "[ ... ]" etc.) + void * pValue; // pointer to value string in JSON text + int error; // error value if dataType == JREAD_ERROR +}; + +//------------------------------------------------------ +// The JSON reader function +// +// - reads a '\0'-terminated JSON text string from pJson +// - traverses the JSON according to the pQuery string +// - returns the result value in pResult +// +// returns: pointer into pJson after the queried value +// +// e.g. +// With JSON like: "{ ..., "key":"value", ... }" +// +// jRead( pJson, "{'key'", &result ); +// returns with: +// result.dataType= JREAD_STRING, result.pValue->'value', result.bytelen=5 +// +char * jRead( char *pJson, char *pQuery, struct jReadElement *pResult ); + +// version of jRead which allows one or more queryParam integers to be substituted +// for array or object indexes marked by a '*' in the query +// +// e.g. jReadParam( pJson, "[*", &resultElement, &arrayIndex ); +// +// *!* CAUTION *!* +// You can supply an array of integers which are indexed for each '*' in pQuery +// however, horrid things will happen if you don't supply enough parameters +// +char * jReadParam( char *pJson, char *pQuery, struct jReadElement *pResult, int *queryParams ); + +// Array Stepping function +// - assumes pJsonArray is JSON source of an array "[ ... ]" +// - returns next element of the array in pResult +// - returns pointer to end of element, to be passed to next call of jReadArrayStep() +// - if end of array is encountered, pResult->error = 13 "End of array found" +// +// e.g. +// With JSON like: "{ ... "arrayInObject":[ elem1,elem2,... ], ... }" +// +// pJson= jRead( pJson, "{'arrayInObject'", &theArray ); +// if( theArray.dataType == JREAD_ARRAY ) +// { +// char *pArray= (char *)theArray.pValue; +// jReadElement arrayElement; +// int index; +// for( index=0; index < theArray.elements; index++ ) +// { +// pArray= jReadArrayStep( pArray, &arrayElement ); +// ... +// +// Note: this significantly speeds up traversing arrays. +// +char *jReadArrayStep( char *pJsonArray, struct jReadElement *pResult ); + + +#define EXPORT_OPTIONAL_FUNCTIONS +#ifdef EXPORT_OPTIONAL_FUNCTIONS + +//------------------------------------------------------ +// Optional Helper Functions +// +long jRead_long( char *pJson, char *pQuery, int *queryParams ); +int jRead_int( char *pJson, char *pQuery, int *queryParams ); +double jRead_double( char *pJson, char *pQuery, int *queryParams ); +int jRead_string( char *pJson, char *pQuery, char *pDest, int destlen, int *queryParams ); + +//------------------------------------------------------ +// Optional String output Functions +// +char *jReadTypeToString( int dataType ); // string describes dataType +char * jReadErrorToString( int error ); // string descibes error code + +//------------------------------------------------------ +// Other jRead utilities which may be useful... +// +char * jRead_atoi( char *p, unsigned int *result ); // string to unsigned int +char * jRead_atol( char *p, long *result ); // string to signed long +char * jRead_atof( char *p, double *result); // string to double (does not do exponents) +int jReadStrcmp( struct jReadElement *j1, struct jReadElement *j2 ); // compare STRING elements + +// copy element to '\0'-terminated buffer +char * jRead_strcpy( char *destBuffer, int destLength, struct jReadElement *pElement ); + +#endif +// end of jRead.h diff --git a/jWrite.c b/jWrite.c new file mode 100644 index 0000000..6ec9be2 --- /dev/null +++ b/jWrite.c @@ -0,0 +1,566 @@ +//Author: Tony Wilk +//Source: https://www.codeproject.com/Articles/887604/jWrite-A-Really-Simple-JSON-Writer-in-C +//LICENSE: The Code Project Open License (CPOL) 1.02 +//see provided file ICENSE_jReadJWrite.html or https://www.codeproject.com/info/cpol10.aspx + +// +// jWrite.c version 1v2 +// +// A *really* simple JSON writer in C +// +// see: jWrite.h for info +// +// TonyWilk, Mar 2015 +// +#define _CRT_SECURE_NO_WARNINGS // stop complaining about deprecated functions + +#include +#include +#include // memset() + +#include "jWrite.h" + +//#include // definintion of uint32_t, int32_t +typedef unsigned int uint32_t; +typedef int int32_t; + + +// the jWrite functions take the above jWriteControl structure pointer +// to maintain state while writing a JSON string. +// +// You can opt to use a single global instance of a jWriteControl structure +// which simplifies the function parameters or to supply your own structure +// +#ifdef JW_GLOBAL_CONTROL_STRUCT +struct jWriteControl g_jWriteControl; // global control struct +#define JWC_DECL // function parameter decl is empty +#define JWC_DECL0 +#define JWC(x) g_jWriteControl.x // functions access global +#define JWC_PARAM // pointer to struct is empty +#define JWC_PARAM0 +#else +#define JWC_DECL struct jWriteControl *jwc, // function parameter is ptr to control struct +#define JWC_DECL0 struct jWriteControl *jwc // function parameter, no params +#define JWC(x) jwc->x // functions use pointer +#define JWC_PARAM jwc, // pointer to stuct +#define JWC_PARAM0 jwc // pointer to stuct, no params +#endif + +//------------------------------------------ +// Internal functions +// +void jwPutch( JWC_DECL char c ); +void jwPutstr( JWC_DECL char *str ); +void jwPutraw( JWC_DECL char *str ); +void modp_itoa10(int32_t value, char* str); +void modp_dtoa2(double value, char* str, int prec); +void jwPretty( JWC_DECL0 ); +enum jwNodeType jwPop( JWC_DECL0 ); +void jwPush( JWC_DECL enum jwNodeType nodeType ); + + +//------------------------------------------ +// jwOpen +// - open writing of JSON starting with rootType = JW_OBJECT or JW_ARRAY +// - initialise with user string buffer of length buflen +// - isPretty=JW_PRETTY adds \n and spaces to prettify output (else JW_COMPACT) +// +void jwOpen( JWC_DECL char *buffer, unsigned int buflen, + enum jwNodeType rootType, int isPretty ) +{ + memset( buffer, 0, buflen ); // zap the whole destination buffer + JWC(buffer)= buffer; + JWC(buflen)= buflen; + JWC(bufp)= buffer; + JWC(nodeStack)[0].nodeType= rootType; + JWC(nodeStack)[0].elementNo= 0; + JWC(stackpos)=0; + JWC(error)= JWRITE_OK; + JWC(callNo)= 1; + JWC(isPretty)= isPretty; + jwPutch( JWC_PARAM (rootType==JW_OBJECT) ? '{' : '[' ); +} + +//------------------------------------------ +// jwClose +// - closes the root JSON object started by jwOpen() +// - returns error code +// +int jwClose( JWC_DECL0 ) +{ + if( JWC(error) == JWRITE_OK ) + { + if( JWC(stackpos) == 0 ) + { + enum jwNodeType node= JWC(nodeStack)[0].nodeType; + if( JWC(isPretty) ) + jwPutch( JWC_PARAM '\n' ); + jwPutch( JWC_PARAM (node == JW_OBJECT) ? '}' : ']'); + }else{ + JWC(error)= JWRITE_NEST_ERROR; // nesting error, not all objects closed when jwClose() called + } + } + return JWC(error); +} + +//------------------------------------------ +// End the current array/object +// +int jwEnd( JWC_DECL0 ) +{ + if( JWC(error) == JWRITE_OK ) + { + enum jwNodeType node; + int lastElemNo= JWC(nodeStack)[JWC(stackpos)].elementNo; + node= jwPop( JWC_PARAM0 ); + if( lastElemNo > 0 ) + jwPretty( JWC_PARAM0 ); + jwPutch( JWC_PARAM (node == JW_OBJECT) ? '}' : ']'); + } + return JWC(error); +} + + +//------------------------------------------ +// jwErrorPos +// - Returns position of error: the nth call to a jWrite function +// +int jwErrorPos( JWC_DECL0 ) +{ + return JWC(callNo); +} + + +//------------------------------------------ +// Object insert functions +// +int _jwObj( JWC_DECL char *key ); + +// put raw string to object (i.e. contents of rawtext without quotes) +// +void jwObj_raw( JWC_DECL char *key, char *rawtext ) +{ + if(_jwObj( JWC_PARAM key ) == JWRITE_OK) + jwPutraw( JWC_PARAM rawtext); +} + +// put "quoted" string to object +// +void jwObj_string( JWC_DECL char *key, char *value ) +{ + if(_jwObj( JWC_PARAM key ) == JWRITE_OK) + jwPutstr( JWC_PARAM value ); +} + +void jwObj_int( JWC_DECL char *key, int value ) +{ + modp_itoa10( value, JWC(tmpbuf) ); + jwObj_raw( JWC_PARAM key, JWC(tmpbuf) ); +} + +void jwObj_double( JWC_DECL char *key, double value ) +{ + modp_dtoa2( value, JWC(tmpbuf), 6 ); + jwObj_raw( JWC_PARAM key, JWC(tmpbuf) ); +} + +void jwObj_bool( JWC_DECL char *key, int oneOrZero ) +{ + jwObj_raw( JWC_PARAM key, (oneOrZero) ? "true" : "false" ); +} + +void jwObj_null( JWC_DECL char *key ) +{ + jwObj_raw( JWC_PARAM key, "null" ); +} + +// put Object in Object +// +void jwObj_object( JWC_DECL char *key ) +{ + if(_jwObj( JWC_PARAM key ) == JWRITE_OK) + { + jwPutch( JWC_PARAM '{' ); + jwPush( JWC_PARAM JW_OBJECT ); + } +} + +// put Array in Object +// +void jwObj_array( JWC_DECL char *key ) +{ + if(_jwObj( JWC_PARAM key ) == JWRITE_OK) + { + jwPutch( JWC_PARAM '[' ); + jwPush( JWC_PARAM JW_ARRAY ); + } +} + +//------------------------------------------ +// Array insert functions +// +int _jwArr( JWC_DECL0 ); + +// put raw string to array (i.e. contents of rawtext without quotes) +// +void jwArr_raw( JWC_DECL char *rawtext ) +{ + if(_jwArr( JWC_PARAM0 ) == JWRITE_OK) + jwPutraw( JWC_PARAM rawtext); +} + +// put "quoted" string to array +// +void jwArr_string( JWC_DECL char *value ) +{ + if(_jwArr( JWC_PARAM0 ) == JWRITE_OK) + jwPutstr( JWC_PARAM value ); +} + +void jwArr_int( JWC_DECL int value ) +{ + modp_itoa10( value, JWC(tmpbuf) ); + jwArr_raw( JWC_PARAM JWC(tmpbuf) ); +} + +void jwArr_double( JWC_DECL double value ) +{ + modp_dtoa2( value, JWC(tmpbuf), 6 ); + jwArr_raw( JWC_PARAM JWC(tmpbuf) ); +} + +void jwArr_bool( JWC_DECL int oneOrZero ) +{ + jwArr_raw( JWC_PARAM (oneOrZero) ? "true" : "false" ); +} + +void jwArr_null( JWC_DECL0 ) +{ + jwArr_raw( JWC_PARAM "null" ); +} + +void jwArr_object( JWC_DECL0 ) +{ + if(_jwArr( JWC_PARAM0 ) == JWRITE_OK) + { + jwPutch( JWC_PARAM '{' ); + jwPush( JWC_PARAM JW_OBJECT ); + } +} + +void jwArr_array( JWC_DECL0 ) +{ + if(_jwArr( JWC_PARAM0 ) == JWRITE_OK) + { + jwPutch( JWC_PARAM '[' ); + jwPush( JWC_PARAM JW_ARRAY ); + } +} + + +//------------------------------------------ +// jwErrorToString +// - returns string describing error code +// +char *jwErrorToString( int err ) +{ + switch( err ) + { + case JWRITE_OK: return "OK"; + case JWRITE_BUF_FULL: return "output buffer full"; + case JWRITE_NOT_ARRAY: return "tried to write Array value into Object"; + case JWRITE_NOT_OBJECT: return "tried to write Object key/value into Array"; + case JWRITE_STACK_FULL: return "array/object nesting > JWRITE_STACK_DEPTH"; + case JWRITE_STACK_EMPTY:return "stack underflow error (too many 'end's)"; + case JWRITE_NEST_ERROR: return "nesting error, not all objects closed when jwClose() called"; + } + return "Unknown error"; +} + +//============================================================================ +// Internal functions +// +void jwPretty( JWC_DECL0 ) +{ + int i; + if( JWC(isPretty) ) + { + jwPutch( JWC_PARAM '\n' ); + for( i=0; i= JWRITE_STACK_DEPTH ) + JWC(error)= JWRITE_STACK_FULL; // array/object nesting > JWRITE_STACK_DEPTH + else + { + JWC(nodeStack[++JWC(stackpos)]).nodeType= nodeType; + JWC(nodeStack[JWC(stackpos)]).elementNo= 0; + } +} + +enum jwNodeType jwPop( JWC_DECL0 ) +{ + enum jwNodeType retval= JWC(nodeStack[JWC(stackpos)]).nodeType; + if( JWC(stackpos) == 0 ) + JWC(error)= JWRITE_STACK_EMPTY; // stack underflow error (too many 'end's) + else + JWC(stackpos)--; + return retval; +} + +void jwPutch( JWC_DECL char c ) +{ + if( (unsigned int)(JWC(bufp) - JWC(buffer)) >= JWC(buflen) ) + { + JWC(error)= JWRITE_BUF_FULL; + }else{ + *JWC(bufp)++ = c; + } +} + +// put string enclosed in quotes +// +void jwPutstr( JWC_DECL char *str ) +{ + jwPutch( JWC_PARAM '\"' ); + while( *str != '\0' ) + jwPutch( JWC_PARAM *str++ ); + jwPutch( JWC_PARAM '\"' ); +} + +// put raw string +// +void jwPutraw( JWC_DECL char *str ) +{ + while( *str != '\0' ) + jwPutch( JWC_PARAM *str++ ); +} + + +// *common Object function* +// - checks error +// - checks current node is OBJECT +// - adds comma if reqd +// - adds "key" : +// +int _jwObj( JWC_DECL char *key ) +{ + if(JWC(error) == JWRITE_OK) + { + JWC(callNo)++; + if( JWC(nodeStack)[JWC(stackpos)].nodeType != JW_OBJECT ) + JWC(error)= JWRITE_NOT_OBJECT; // tried to write Object key/value into Array + else if( JWC(nodeStack)[JWC(stackpos)].elementNo++ > 0 ) + jwPutch( JWC_PARAM ',' ); + jwPretty( JWC_PARAM0 ); + jwPutstr( JWC_PARAM key ); + jwPutch( JWC_PARAM ':' ); + if( JWC(isPretty) ) + jwPutch( JWC_PARAM ' ' ); + } + return JWC(error); +} + +// *common Array function* +// - checks error +// - checks current node is ARRAY +// - adds comma if reqd +// +int _jwArr( JWC_DECL0 ) +{ + if(JWC(error) == JWRITE_OK) + { + JWC(callNo)++; + if( JWC(nodeStack)[JWC(stackpos)].nodeType != JW_ARRAY ) + JWC(error)= JWRITE_NOT_ARRAY; // tried to write array value into Object + else if( JWC(nodeStack)[JWC(stackpos)].elementNo++ > 0 ) + jwPutch( JWC_PARAM ',' ); + jwPretty( JWC_PARAM0 ); + } + return JWC(error); +} + +//================================================================= +// +// modp value-to-string functions +// - modified for C89 +// +// We use these functions as they are a lot faster than sprintf() +// +// Origin of these routines: +/* + *

+ * Copyright © 2007, Nick Galbreath -- nickg [at] modp [dot] com
+ * All rights reserved.
+ * http://code.google.com/p/stringencoders/
+ * Released under the bsd license.
+ * 
+ */ + +static void strreverse(char* begin, char* end) +{ + char aux; + while (end > begin) + aux = *end, *end-- = *begin, *begin++ = aux; +} + +/** \brief convert an signed integer to char buffer + * + * \param[in] value + * \param[out] buf the output buffer. Should be 16 chars or more. + */ +void modp_itoa10(int32_t value, char* str) +{ + char* wstr=str; + // Take care of sign + unsigned int uvalue = (value < 0) ? -value : value; + // Conversion. Number is reversed. + do *wstr++ = (char)(48 + (uvalue % 10)); while(uvalue /= 10); + if (value < 0) *wstr++ = '-'; + *wstr='\0'; + + // Reverse string + strreverse(str,wstr-1); +} + +/** + * Powers of 10 + * 10^0 to 10^9 + */ +static const double pow10[] = {1, 10, 100, 1000, 10000, 100000, 1000000, + 10000000, 100000000, 1000000000}; + +/** \brief convert a floating point number to char buffer with a + * variable-precision format, and no trailing zeros + * + * This is similar to "%.[0-9]f" in the printf style, except it will + * NOT include trailing zeros after the decimal point. This type + * of format oddly does not exists with printf. + * + * If the input value is greater than 1<<31, then the output format + * will be switched exponential format. + * + * \param[in] value + * \param[out] buf The allocated output buffer. Should be 32 chars or more. + * \param[in] precision Number of digits to the right of the decimal point. + * Can only be 0-9. + */ +void modp_dtoa2(double value, char* str, int prec) +{ + /* if input is larger than thres_max, revert to exponential */ + const double thres_max = (double)(0x7FFFFFFF); + int count; + double diff = 0.0; + char* wstr = str; + int neg= 0; + int whole; + double tmp; + uint32_t frac; + + /* Hacky test for NaN + * under -fast-math this won't work, but then you also won't + * have correct nan values anyways. The alternative is + * to link with libmath (bad) or hack IEEE double bits (bad) + */ + if (! (value == value)) { + str[0] = 'n'; str[1] = 'a'; str[2] = 'n'; str[3] = '\0'; + return; + } + + if (prec < 0) { + prec = 0; + } else if (prec > 9) { + /* precision of >= 10 can lead to overflow errors */ + prec = 9; + } + + /* we'll work in positive values and deal with the + negative sign issue later */ + if (value < 0) { + neg = 1; + value = -value; + } + + + whole = (int) value; + tmp = (value - whole) * pow10[prec]; + frac = (uint32_t)(tmp); + diff = tmp - frac; + + if (diff > 0.5) { + ++frac; + /* handle rollover, e.g. case 0.99 with prec 1 is 1.0 */ + if (frac >= pow10[prec]) { + frac = 0; + ++whole; + } + } else if (diff == 0.5 && ((frac == 0) || (frac & 1))) { + /* if halfway, round up if odd, OR + if last digit is 0. That last part is strange */ + ++frac; + } + + /* for very large numbers switch back to native sprintf for exponentials. + anyone want to write code to replace this? */ + /* + normal printf behavior is to print EVERY whole number digit + which can be 100s of characters overflowing your buffers == bad + */ + if (value > thres_max) { + sprintf(str, "%e", neg ? -value : value); + return; + } + + if (prec == 0) { + diff = value - whole; + if (diff > 0.5) { + /* greater than 0.5, round up, e.g. 1.6 -> 2 */ + ++whole; + } else if (diff == 0.5 && (whole & 1)) { + /* exactly 0.5 and ODD, then round up */ + /* 1.5 -> 2, but 2.5 -> 2 */ + ++whole; + } + + //vvvvvvvvvvvvvvvvvvv Diff from modp_dto2 + } else if (frac) { + count = prec; + // now do fractional part, as an unsigned number + // we know it is not 0 but we can have leading zeros, these + // should be removed + while (!(frac % 10)) { + --count; + frac /= 10; + } + //^^^^^^^^^^^^^^^^^^^ Diff from modp_dto2 + + // now do fractional part, as an unsigned number + do { + --count; + *wstr++ = (char)(48 + (frac % 10)); + } while (frac /= 10); + // add extra 0s + while (count-- > 0) *wstr++ = '0'; + // add decimal + *wstr++ = '.'; + } + + // do whole part + // Take care of sign + // Conversion. Number is reversed. + do *wstr++ = (char)(48 + (whole % 10)); while (whole /= 10); + if (neg) { + *wstr++ = '-'; + } + *wstr='\0'; + strreverse(str, wstr-1); +} +//================================================================= + +/* end of jWrite.c */ diff --git a/jWrite.h b/jWrite.h new file mode 100644 index 0000000..a7991cf --- /dev/null +++ b/jWrite.h @@ -0,0 +1,218 @@ +//Author: Tony Wilk +//Source: https://www.codeproject.com/Articles/887604/jWrite-A-Really-Simple-JSON-Writer-in-C +//LICENSE: The Code Project Open License (CPOL) 1.02 +//see provided file ICENSE_jReadJWrite.html or https://www.codeproject.com/info/cpol10.aspx + +// +// jWrite.h +// +// A *really* simple JSON writer in C (C89) +// - a collection of functions to generate JSON semi-automatically +// +// The idea is to simplify writing native C values into a JSON string and +// to provide some error trapping to ensure that the result is valid JSON. +// +// Example: +// jwOpen( buffer, buflen, JW_OBJECT, JW_PRETTY ); // open root node as object +// jwObj_string( "key", "value" ); +// jwObj_int( "int", 1 ); +// jwObj_array( "anArray"); +// jwArr_int( 0 ); +// jwArr_int( 1 ); +// jwArr_int( 2 ); +// jwEnd(); +// err= jwClose(); // close root object +// +// results in: +// +// { +// "key": "value", +// "int": 1, +// "anArray": [ +// 0, +// 1, +// 2 +// ] +// } +// +// Note that jWrite handles string quoting and getting commas in the right place. +// If the sequence of calls is incorrect +// e.g. +// jwOpen( buffer, buflen, JW_OBJECT, 1 ); +// jwObj_string( "key", "value" ); +// jwArr_int( 0 ); +// ... +// +// then the error code returned from jwClose() would indicate that you attempted to +// put an array element into an object (instead of a key:value pair) +// To locate the error, the supplied buffer has the JSON created upto the error point +// and a call to jwErrorPos() would return the function call at which the error occurred +// - in this case 3, the 3rd function call "jwArr_int(0)" is not correct at this point. +// +// The root JSON type can be JW_OBJECT or JW_ARRAY. +// +// For more information on each function, see the prototypes below. +// +// +// GLOBAL vs. Application-Supplied Control Structure +// ------------------------------------------------- +// jWrite requires a jWriteControl structure to save the internal state. +// For many applications it is much simpler for this to be a global variable as +// used by the above examples. +// +// To use multiple instances of jWrite, an application has to supply unique instances +// of jWriteControl structures. +// +// This feature is enabled by commenting out the definition of JW_GLOBAL_CONTROL_STRUCT +// +// All the jWrite functions then take an additional parameter: a ptr to the structure +// e.g. +// struct jWriteControl jwc; +// +// jwOpen( &jwc, buffer, buflen, JW_OBJECT, 1 ); +// jwObj_string( &jwc, "key", "value" ); +// jwObj_int( &jwc, "int", 1 ); +// jwObj_array( &jwc, "anArray"); +// jwArr_int( &jwc, 0 ); +// jwArr_int( &jwc, 1 ); +// jwArr_int( &jwc, 2 ); +// jwEnd( &jwc ); +// err= jwClose( &jwc ); +// +// - which is more flexible, but a pain to type in ! +// +// TonyWilk, Mar 2015 +// +// +#define JW_GLOBAL_CONTROL_STRUCT // <--- comment this out to use applic-supplied jWriteControl + +#define JWRITE_STACK_DEPTH 32 // max nesting depth of objects/arrays + +#define JW_COMPACT 0 // output string control for jwOpen() +#define JW_PRETTY 1 // pretty adds \n and indentation + +enum jwNodeType{ + JW_OBJECT= 1, + JW_ARRAY +}; + +struct jwNodeStack{ + enum jwNodeType nodeType; + int elementNo; +}; + +struct jWriteControl{ + char *buffer; // pointer to application's buffer + unsigned int buflen; // length of buffer + char *bufp; // current write position in buffer + char tmpbuf[32]; // local buffer for int/double convertions + int error; // error code + int callNo; // API call on which error occurred + struct jwNodeStack nodeStack[JWRITE_STACK_DEPTH]; // stack of array/object nodes + int stackpos; + int isPretty; // 1= pretty output (inserts \n and spaces) +}; + +// Error Codes +// ----------- +#define JWRITE_OK 0 +#define JWRITE_BUF_FULL 1 // output buffer full +#define JWRITE_NOT_ARRAY 2 // tried to write Array value into Object +#define JWRITE_NOT_OBJECT 3 // tried to write Object key/value into Array +#define JWRITE_STACK_FULL 4 // array/object nesting > JWRITE_STACK_DEPTH +#define JWRITE_STACK_EMPTY 5 // stack underflow error (too many 'end's) +#define JWRITE_NEST_ERROR 6 // nesting error, not all objects closed when jwClose() called + + +// API functions +// ------------- + +// Returns '\0'-termianted string describing the error (as returned by jwClose()) +// +char *jwErrorToString( int err ); + + +#ifdef JW_GLOBAL_CONTROL_STRUCT /* USING GLOBAL g_jWriteControl */ + +// jwOpen +// - initialises jWrite with the application supplied 'buffer' of length 'buflen' +// in operation, the buffer will always contain a valid '\0'-terminated string +// - jWrite will not overrun the buffer (it returns an "output buffer full" error) +// - rootType is the base JSON type: JW_OBJECT or JW_ARRAY +// - isPretty controls 'prettifying' the output: JW_PRETTY or JW_COMPACT +void jwOpen( char *buffer, unsigned int buflen, enum jwNodeType rootType, int isPretty ); + +// jwClose +// - closes the element opened by jwOpen() +// - returns error code (0 = JWRITE_OK) +// - after an error, all following jWrite calls are skipped internally +// so the error code is for the first error detected +int jwClose( ); + +// jwErrorPos +// - if jwClose returned an error, this function returns the number of the jWrite function call +// which caused that error. +int jwErrorPos( ); + +// Object insertion functions +// - used to insert "key":"value" pairs into an object +// +void jwObj_string( char *key, char *value ); +void jwObj_int( char *key, int value ); +void jwObj_double( char *key, double value ); +void jwObj_bool( char *key, int oneOrZero ); +void jwObj_null( char *key ); +void jwObj_object( char *key ); +void jwObj_array( char *key ); + +// Array insertion functions +// - used to insert "value" elements into an array +// +void jwArr_string( char *value ); +void jwArr_int( int value ); +void jwArr_double( double value ); +void jwArr_bool( int oneOrZero ); +void jwArr_null( ); +void jwArr_object( ); +void jwArr_array( ); + +// jwEnd +// - defines the end of an Object or Array definition +int jwEnd( ); + + +// these 'raw' routines write the JSON value as the contents of rawtext +// i.e. enclosing quotes are not added +// - use if your app. supplies its own value->string functions +// +void jwObj_raw( char *key, char *rawtext ); +void jwArr_raw( char *rawtext ); + +#else /* JW_GLOBAL_CONTROL_STRUCT not defined */ +// Same API functions with app-supplied control struct option +// +void jwOpen( struct jWriteControl *jwc, char *buffer, unsigned int buflen, enum jwNodeType rootType, int isPretty ); +int jwClose( struct jWriteControl *jwc ); +int jwErrorPos( struct jWriteControl *jwc ); +void jwObj_string( struct jWriteControl *jwc, char *key, char *value ); +void jwObj_int( struct jWriteControl *jwc, char *key, int value ); +void jwObj_double( struct jWriteControl *jwc, char *key, double value ); +void jwObj_bool( struct jWriteControl *jwc, char *key, int oneOrZero ); +void jwObj_null( struct jWriteControl *jwc, char *key ); +void jwObj_object( struct jWriteControl *jwc, char *key ); +void jwObj_array( struct jWriteControl *jwc, char *key ); +void jwArr_string( struct jWriteControl *jwc, char *value ); +void jwArr_int( struct jWriteControl *jwc, int value ); +void jwArr_double( struct jWriteControl *jwc, double value ); +void jwArr_bool( struct jWriteControl *jwc, int oneOrZero ); +void jwArr_null( struct jWriteControl *jwc ); +void jwArr_object( struct jWriteControl *jwc ); +void jwArr_array( struct jWriteControl *jwc ); +int jwEnd( struct jWriteControl *jwc ); +void jwObj_raw( struct jWriteControl *jwc, char *key, char *rawtext ); +void jwArr_raw( struct jWriteControl *jwc, char *rawtext ); + +#endif /* JW_GLOBAL_CONTROL_STRUCT */ + + +/* end of jWrite.h */ diff --git a/jackclient.c b/jackclient.c new file mode 100644 index 0000000..3fb57f0 --- /dev/null +++ b/jackclient.c @@ -0,0 +1,266 @@ +//Standard lib +#include //memcpy +#include //print error messages +#include + + +//Third party +#include +#include +#include +#include + +//Our own files +#include "jackclient.h" +#include "constants.h" +#include "programstate.h" + +extern ProgramState programState; + +static jack_client_t* client; +//static jack_ringbuffer_t *ringbuffer = NULL; + +jack_ringbuffer_t *allRingbuffers[VIS_PORTS]; +jack_port_t *allPorts[VIS_PORTS]; + +static pthread_mutex_t msg_thread_lock = PTHREAD_MUTEX_INITIALIZER; +static pthread_cond_t data_ready = PTHREAD_COND_INITIALIZER; + +#define RBSIZE 512 + +typedef struct { + uint8_t buffer[128]; + uint32_t size; +} midimsg; + + +int process (jack_nframes_t frames, void* arg) { + void* buffer; + jack_nframes_t N; + jack_nframes_t i; + jack_port_t* port; + jack_ringbuffer_t* rb=NULL; + + for (int portnum=0; portnum= sizeof(midimsg)) { + midimsg message; + message.size = event.size; + memcpy (message.buffer, event.buffer, MAX(sizeof(message.buffer), event.size)); + jack_ringbuffer_write (rb, (void *) &message, sizeof(midimsg)); + } + } + } + + + if (pthread_mutex_trylock (&msg_thread_lock) == 0) { + pthread_cond_signal (&data_ready); + pthread_mutex_unlock (&msg_thread_lock); + } + + return 0; +} + +static void handleMessage (Note *allGUINotes, int portnum, midimsg* event) { + if (event->size == 0) { + return; + } + + uint8_t type = event->buffer[0] & 0xf0; + uint8_t channel = event->buffer[0] & 0xf; + Note * note; + + switch (type) { + case 0x90: + //assert (event->size == 3); + //printf (" note on (channel %2d): pitch %3d, velocity %3d\n", channel, event->buffer[1], event->buffer[2]); + programState.portActivity[portnum] += 1; + note = &allGUINotes[portnum*128 + event->buffer[1]]; + note->active = 1; + note->countdown = 1.0f; + note->velocity = event->buffer[2]; + note->pitch = event->buffer[1]; + note->port = portnum; + break; + case 0x80: + //assert (event->size == 3); + //printf (" note off (channel %2d): pitch %3d, velocity %3d\n", channel, event->buffer[1], event->buffer[2]); + programState.portActivity[portnum] -= 1; + if (programState.portActivity[portnum] < 1) { programState.portActivity[portnum] = 0;} + note = &allGUINotes[portnum*128 + event->buffer[1]]; + note->countdown = 0.999f; //GUI will reduce that to 0 on its own as fade-out effect + //Do NOT set to inactive. Note-Off triggers a graphical fadeout, only when that is over it is inactive. + break; + //case 0xb0: + //assert (event->size == 3); + //printf (" control change (channel %2d): controller %3d, value %3d", channel, event->buffer[1], event->buffer[2]); + // break; + default: + break; + } +} + +void mainLoop_processMidiMessages(Note *allGUINotes) { + + for (int portnum=0; portnum 1.0d) { //comparing to 0 does not work + programState.bpm = pos.beats_per_minute; + } + else + { + programState.bpm = 120.0d; + } + +} + + +void ourConnectCallback(jack_port_id_t a, jack_port_id_t b, int connect, void *arg) { + + //On each connection change go through our ports and check the situation. + //Only the first port is enough for our purposes + + //TODO: optimisation opportunity: keep a list of our port ids and check that first. + + for (int portnum=0; portnum non-const + programState.connectedPortNames[portnum] = externalPrettyName; + //if (externalPrettyName) jack_free(externalPrettyName); //TODO: If I free that the name either vanishes, segfaults, is wrong or garbage or it is always the same. No matter what string copy, conversion etc. I tried + if (externalType) jack_free(externalType); + } + else { // No Metadata for this port found + programState.connectedPortNames[portnum] = connectedPorts[0]; + } + } + else + { + programState.connectedPortNames[portnum] = ""; //Reset + } + jack_free(connectedPorts); + } + +} + +void createJackClient() { + + int errorCode; + + client = jack_client_open (programState.name, JackNullOption, NULL); + if (client == NULL) { + fprintf (stderr, "Could not create JACK client.\n"); + exit (EXIT_FAILURE); + } + + jack_set_process_callback (client, process, 0); + + for (int portnum=0; portnum + + +int process (jack_nframes_t frames, void* arg); + +void createJackClient(); +void closeJackClient(); +void mainLoop_processMidiMessages(Note *allGUINotes); +void toggleTransport(); +void seekToStart(); +//char * positionAsClock(); +void mainLoop_collectTimingAndTransportInProgramState(); + + +#endif // not defined JACKCLIENT_H diff --git a/main.c b/main.c new file mode 100644 index 0000000..930c25f --- /dev/null +++ b/main.c @@ -0,0 +1,405 @@ +//Standard lib +#include +#include + +//Third party +#include "raylib.h" //systemlib +#include "raygui.h" //included in our source +#include "nsm.h" //included in our source + +//Our own files +#include "constants.h" +#include "programstate.h" +#include "draw.h" +#include "jackclient.h" +#include "gui.h" +#include "camera.h" + +#define OUR_NAME "The Grand Visualizer Show" + +//Internal setup +static bool readySwitch = false; //switched on once nsm is ready or we start ourselves +extern ProgramState programState; + +//NSM setup +static const char *nsm_url; +static nsm_client_t *nsm = 0; +static int wait_nsm = 1; + +void callback_nsm_show( void *userdata ) { + UnhideWindow(); + programState.applicationWindowVisible = true; //saved. Restored on program start. + nsm_send_is_shown(nsm); +} + +void callback_nsm_hide( void *userdata ) { + HideWindow(); + programState.applicationWindowVisible = false; //saved. Restored on program start. + nsm_send_is_hidden(nsm); +} + +int callback_nsm_save(char **out_msg,void *userdata) { + saveStateToFile(); + return ERR_OK; +} + +bool poll_nsm() { + if (nsm) + { + nsm_check_nowait(nsm); + return true; + } + return false; +} + +int callback_nsm_open(const char *save_file_path, const char *display_name, const char *client_id, char **out_msg, void *userdata) { + wait_nsm = 0; + + InitWindow(1920, 1080, client_id); + initProgramState(true, save_file_path, client_id); //true = nsm mode + printf("NSM Save File Path: %s, Client Id: %s\n", save_file_path, client_id); + + if (strstr(nsm_get_session_manager_features(nsm), ":optional-gui:" )) { + nsm_set_show_callback(nsm, callback_nsm_show, 0); + nsm_set_hide_callback(nsm, callback_nsm_hide, 0); + } + + readySwitch = true; + return ERR_OK; +} + + +void doExit() { + if (!nsm_url) { + saveStateToFile(); + } + closeJackClient(); + //UnloadRenderTexture(renderTarget); // Unload render texture + //UnloadShader(shader); + free(programState.clockString); + free(programState.name); + if (programState.nsm) + free(programState.filePath); + CloseWindow(); // Close window and OpenGL context +} + +void signalExit(int signal) { + doExit(); +} + +int main(int argc, char **argv) { + + signal(SIGINT, signalExit); + signal(SIGTERM, signalExit); + + //////////////////////////////// + // Init Window (and RayLib) first because file load already creates textures or Commandline and Internal Program State + //////////////////////////////// + //SetConfigFlags(FLAG_WINDOW_RESIZABLE); //When a tiling window manager releases from tiled to floating the window dimensions will be honored. + SetConfigFlags(FLAG_MSAA_4X_HINT); // Enable Multi Sampling Anti Aliasing 4x (if available) + //Init Window itself is right before setting the name, see below NSM mode callback and standalone branch + + + + //////////////////////////////// + // Setup NSM or Commandline and Internal Program State + //////////////////////////////// + + //Debug test filePath = "/home/nils/temp/hallo.json"; + nsm_url = getenv("NSM_URL"); + //NSM Mode + if (nsm_url) { + nsm = nsm_new(); + nsm_set_open_callback(nsm, callback_nsm_open, 0); //sets filePath + nsm_set_save_callback(nsm, callback_nsm_save, 0); + int nsmInitErr = nsm_init(nsm, nsm_url); + if (nsmInitErr == 0) { + nsm_send_announce(nsm, OUR_NAME, ":optional-gui:", argv[0]); + } + else { + nsm_free( nsm ); + nsm = 0; + printf("Tried to start in NSM, but failed.\n"); + return 0; //End program here. This was started under NSM so we won't fall back to standalone without telling + } + } + //Standalone Mode + else { + const char * filePath; + readySwitch = true; + switch(argc) { //TODO: simple parser for now. Just one file name or nothing. + case 1: + filePath = ""; + break; + case 2: + filePath = argv[1]; //TODO: Make sure this is a .json file extension? + break; + default: + printf("Unsupported arguments. %s filename.json\n", argv[0]); + return 0; + } + + InitWindow(1920, 1080, OUR_NAME); + initProgramState(false, filePath, OUR_NAME); //false = no nsm + } + + while (!readySwitch) { + poll_nsm(); //wait for nsm. + } + + + + + //////////////////////////////// + // Setup Audio/Video + //////////////////////////////// + createJackClient(); + + Note allGUINotes[VIS_PORTS*128]; + + for (int port=0; porthide machen, so wie Qt. Ich hab die funktionalität erstmal rausgenommen. An WindowShouldClose() hängt noch ne ganze menge mehr dran, die ganze KeyPress logic. Das kann ich nicht umschreiben oder hijacken. Ergo ist mein Programm schließbar. Na dann soll es zumindest den letzten Stand speichern. Vielleicht kann ich glfw direkt benutzen? + #include +* +* Richtiger commandline parser mit usage und --help und --version +* +* Weil rayaudio mit drin ist brauch ich momentan celt und opus als libs. Das rauskriegen. Das liegt aber daran wie raylib kompiliert wurde. Also wenn ich statisch linke... + +* Es gibt bestimmt so open game art leute oder demo-scene leute, die nen Music Vizualizer mit diskreten informationen (midi) machen wollen +* Modus oder parameter per CC verändern. Ganzer Modus ist vielleicht nicht so appealing, aber die Leuchtintensität wäre das ganz cool. z.B. auf CC7 Volume. Oder Wobbly Notes auf Modwheel. Das passt auch zur Lightshow +* Man muss nicht zwingend reale Musik hier reinschicken. Man kann auch ne Light-Show machen. +* Jeder Modus braucht aber einen Docstring, in dem stehen muss wie es gedacht ist. Ob das jetzt 16 channel music trigger ist oder per channel light/dance show etc. +* Jeder Modus kann ja einfach so, ohne Skriptsprache oder config datei, eigene GUI Felder machen. Oberer Bildschirmrand ist für die, untere Hälfte ist generisch. Muss man ja nicht übertreiben. + + * Zeit ist das lineare Element, nicht rhythmus. + * Wie kriegt man Lookahead hin? Für live input geht das also nicht. + * Man muss das stück zweimal laufen lassen und beim zweiten mal wird dann + * gerendert. Oder es wird eine statische save-datei erzeugt mit dem zeitindex + * und beim render-durchlauf wird nur mit jack transport gestartet und gestoppt. + * + * CC Controls sind schon cooler als GUI controls. Dann kann man da sachen stufenlos einstellen mit hardware controllern. Dann kann man auch so One-Shot effekte Feuern, wie ne richtige Lightshow. "Add Random Firework Shot" + * MIDI Learn? So Effekt-Trigger erfordern dann nen Layermodus. Die sind einfach oben drauf. + * + * Latency look ahead 30 sekunden, eine Minute. Für Videos, wenn nix live gespielt wird. Dann kann man sehen was kommt und der playback cursor ist in der mitte. Wir sind das tool, dass die latency reported. + * Gibt es tools, die meinen Code und das Programm auf RT tauglichkeit testen können? + * https://github.com/fundamental/stoat + + * Text-Einblendungen ("So groß wie möglich" und "Feste Größe mit Wordwrap") über JACK Meta Data, midi karaoke?, spezialport? oder sonst wie? Dann können Programme ihre Titel zeigen. + * Laufschrift unten drunter im DEMO-Scene style + * + * Es kann auch einen modus geben mit Spezial-Animationen von Sprites oder 3D Models, der muss dann aber extra per MIDI Spur programmiert werden mit speziellen werten nur für unser Programm. + * SNES Sprites mit Tanzschritten oder so. + * Oder der Winamp 3D Bär + * + * In-Scale Mode. Man sucht sich eine Tonart aus und das wird darauf gemappt. + * Die Notenbreite kann ruhig mehr ausnutzen. Muss natürlich auf die Fenstergröße skaliert sein. Das passt auch dazu wenn bestimmte Tracks nicht verbunden sind. + * Nicht verbundene Tracks könnte auch von BG-ALTERNATIVE auf BG geschaltet werden. Not Connected: Don't treat differently (default), BG ("deactivated"), Omit + * + * Modus Slideshow: Zeige Bilder in einer Reihenfolge. Da wir ja in NSM sind kann man das einfach reinkopieren. der bleibt beim letzten bild stehen oder wrap around. Jede Note ist ein Impuls. Modus 2: 127 Bilder, jeder Pitch ist 000.png bis 127.png + * + * CC Switch für Modus Switch (direktanwahl) wäre schon cool. + * Kann ich parallel malen? Technisch schon, aber nicht mit den noten. die sind momentan an einer position. Ich bräuchte sonst Rects für jede Variante. Und die müssten auch alle immer mit aktiv und countdown parallel verändert werden. Das klingt aber machbar. + * Das sind meine Layer. Dann brauch ich nur noch nen Z Order die vom user einstellbar ist. + * JACK schreibt trotzdem immer in den gleichen Array. Der ist dann getrennt von den x,y position. Evtl. önnte ich es auch so machen, dass statt ALLE NOTEN IMMER. Immer nur die in der Datenstruktur sind, die gerade aktiv sind. Das ist vielleicht mit dem zugriff schwieriger? + * + * Widget mit Repositionierbaren Listenposition, die an und aus sind. + * + * Grafiken, .png und .apng müssen transparenz unterstützen. Dann kann man daraus sowas wie titel und "DANCE!" machen, die mit dem Layer/Overlay Modus oben drüben liegen. + * + * Vollbildauflösung muss einstellbar sein. Wird im Save File gespeichert. + * + * Bilder und Grafiken von Instrumenten mit Griffzeichnungen + * Akkord-Analyse für Gitarren. + * + * RayLib bug. Wenn wir hidden sind und closeWindow machen kommt: WARNING: GLFW: Error: 65537 Description: The GLFW library is not initialized + * Leider bringt es auch nix vorher das window auf show zu machen. + * + * Readme: + * Name: The Grand Visualizer Show (TGVS) + * Englischer Name, weil das kein Teil der LSS ist. + * Es ist für die eigenen Songs gedacht, am Ende der Production-Phase. + * Man hat Midi Ausgänge und einzelspuren oder kann zur Not einzelne Spuren mit Aubio in Midi-Signale umwandeln. + * + * Ein Instrument for Jack Midi Port. Wenn das ein midi-channel file ist dann muss man vorher splitten. + * Control-Ports braucht es nicht. Dafür gibt es die nicht belegten CCs? Oder ich suche mir davon welche aus, dann muss ich nicht alle 128 abfragen für alle Ports? + * Am Ende des Tages gibt es kein universelles Belegungsschema für die Draw Modes. Die müssen halt gelernt werden. + + * If further developed at all, this application is bound to run into feature-heaven/hell. + * There are so many possible ideas and variations how to visualize, and we want them all! + * With progressing development you can expect a nightmare amount of GUI controls, different rules + * and behaviour for different program modes and one can only hope that at least the basic drawing + * modes are straightforward without the need for a video tutorial to just see something on the screen. + * Be warned: Persons who use the words "KISS" or "UNIX PHILOSOPHY" will be sighed at! :) + +winkel für rotation: 360* / 128 = 2.8125° pro midi Step . 64 = 180° . 127 = 357,1875° + +* Ist der Sprite Overlay was anderes als die Slideshow? Ja, slideshow ist noten-ports, weil das sehr viel einfacher ist für den benutzer + +Sprites und Kontrollport +* +* Die Kamera wird über einen speziellen Midi-Kontrollport gesteuert. Alle Parameter absolut (0% links, 64 = Mitte, 127 = 100% rechts des Bildschirm) und Relativ (CC unter 64 = gehe nach links, CC=64 nix, CC über 64=gehe nach rechts) +* +* +*Es gibt Sprites. Das sind bilder vom Hintergrundbild bis kleine Elemente. Man kann die mit der Maus steuern, drag and drop zum platzieren. Die anderen controls muss man sich dann überlegen. +* Default sind die immer bei 0,0. Die können skaliert werden, mit aspect ratio, auf volle breite. Dann macht natürlich zoom nix mehr. Aber das ist der einfachste Fall. einfach 1920x1080 bilder reinladen und gut ist. +* +* Es gibt 128 Sprites. Einen Pro Pitch. Die sind im Control Port. +* Der momentan zu kontrollierende Sprite wird per Midi-Note ausgewählt. Alle Sprites die momentan Note On sind hören! :) Ne halt, das ist schwierig mit nem Hardware controller? ne, eigentlich geht das.. +* Die Kamera ist fest auf CC0-4 und der ist es egal ob note on oder nicht. + +* Sprites sind in der Kamera mit drin? +* Sprites haben tilesize und tileindex. Per default ist das auf 100% und 0 +* +* +* CCs sind auf Sprites aufgeteilt. Es gibt 12 Stück mit je 10 CCs. +* Wird einfach durchnummeriert. Wenn das irgendwann nicht reicht mach ich einfach nen 2. Sprite Port auf. +* 8 CCs am Ende sind frei. +* Sprite Z Order ist implizit. Höchster Sprite ist ganz oben. Wird aber in foreground und background getrennt. +* Sprite CC Parameter: +* +* x abs in % +* y abs in % +* x delta relative, 64=0 , nach links ist minus pixel, nacht rechts ist plus pixel +* y delta +* zoom. 64 = Default +* Opacity +* Rotation. 0 = 0° default, ab dann wird nach rechts gedreht und 127 ist dann knapp vor 360° +* tileindex . default 0 +* Color/Hue. Irgendwie einen Regler zum einfärben +* RESERVED FOR FUTURE USE + + +Bilder-Slideshow ist die alphabetische Liste in einem DIR. Ein CC o.ä. switched zum nächsten Bild. Es gibt eine Überblendungseinstellung, wie lange (und mit welchem Effekt?) gecrossfaded wird. Das kann natürlich nur NACH dem Signal kommmen, weil wir keine künstliche Latenz +haben. Da die Slideshow aber sowieso bewusst midi-programmiert werden muss vom user kann das auch einfach vor der Zeit eingestellt werden, immer auf die vier, und unser effekt braucht dann halt einen Schlag bei 120 bpm. +*/ diff --git a/nsm.h b/nsm.h new file mode 100644 index 0000000..3b9dc4c --- /dev/null +++ b/nsm.h @@ -0,0 +1,689 @@ + +/*************************************************************************/ +/* Copyright (C) 2012 Jonathan Moore Liles */ +/* Copyright (C) 2020- Nils Hilbricht */ +/* */ +/* Permission to use, copy, modify, and/or distribute this software for */ +/* any purpose with or without fee is hereby granted, provided that the */ +/* above copyright notice and this permission notice appear in all */ +/* copies. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL */ +/* WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED */ +/* WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE */ +/* AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL */ +/* DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR */ +/* PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER */ +/* TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR */ +/* PERFORMANCE OF THIS SOFTWARE. */ +/*************************************************************************/ + + +/*************************************************************************/ +/* A simple, callback based C API for NSM clients. */ +/* */ +/* Simplified Example: */ +/* */ +/* #include "nsm.h" */ +/* */ +/* static nsm_client_t *nsm = 0; */ +/* static int wait_nsm = 1; */ +/* */ +/* int */ +/* cb_nsm_open ( const char *save_file_path, //See API Docs 2.2.2 */ +/* const char *display_name, //Not useful */ +/* const char *client_id, //Use as JACK Client Name */ +/* char **out_msg, */ +/* void *userdata ) */ +/* { */ +/* do_open_stuff(); //Your own function */ +/* wait_nsm = 0; */ +/* return ERR_OK; */ +/* } */ +/* */ +/* int */ +/* cb_nsm_save ( char **out_msg, */ +/* void *userdata ) */ +/* { */ +/* do_save_stuff(); //Your own function */ +/* return ERR_OK; */ +/* } */ +/* */ +/* void */ +/* cb_nsm_show ( void *userdata ) */ +/* { */ +/* do_show_ui(); //Your own function */ +/* nsm_send_is_shown ( nsm ); */ +/* } */ +/* */ +/* void */ +/* cb_nsm_hide ( void *userdata ) */ +/* { */ +/* do_hide_ui(); //Your own function */ +/* nsm_send_is_hidden ( nsm ); */ +/* } */ +/* */ +/* gboolean */ +/* poll_nsm() */ +/* { */ +/* if ( nsm ) */ +/* { */ +/* nsm_check_nowait( nsm ); */ +/* return true; */ +/* } */ +/* return false; */ +/* } */ +/* */ +/* int main( int argc, char **argv ) */ +/* { */ +/* const char *nsm_url = getenv( "NSM_URL" ); */ +/* */ +/* if ( nsm_url ) */ +/* { */ +/* nsm = nsm_new(); */ +/* */ +/* nsm_set_open_callback( nsm, cb_nsm_open, 0 ); */ +/* nsm_set_save_callback( nsm, cb_nsm_save, 0 ); */ +/* */ +/* if ( 0 == nsm_init( nsm, nsm_url ) ) */ +/* { */ +/* nsm_send_announce( nsm, "FOO", ":optional-gui:", argv[0] );*/ +/* */ +/* ********************************************************************** */ +/* This will block for at most 100 sec and */ +/* waiting for the NSM server open callback. */ +/* DISCLAIMER: YOU MAY NOT NEED TO DO THAT. */ +/* ********************************************************************** */ +/* */ +/* int timeout = 0; */ +/* while ( wait_nsm ) */ +/* { */ +/* nsm_check_wait( nsm, 500 ); */ +/* timeout += 1; */ +/* if ( timeout > 200 ) */ +/* exit ( 1 ); */ +/* } */ +/* */ +/* ********************************************************************** */ +/* This will check if the server support optional-gui */ +/* and connect the callbacks when support is found. */ +/* If you don't use the above blocking block */ +/* this could be done in cb_nsm_open() as well. */ +/* DISCLAIMER: YOU MAY NOT NEED TO DO THAT. */ +/* ********************************************************************** */ +/* */ +/* if ( strstr( nsm_get_session_manager_features ( nsm ), */ +/* ":optional-gui:" ) ) */ +/* { */ +/* nsm_set_show_callback( nsm, cb_nsm_show, 0 ); */ +/* nsm_set_hide_callback( nsm, cb_nsm_hide, 0 ); */ +/* } */ +/* */ +/* ********************************************************************** */ +/* */ +/* do_timeout_add( 200, poll_nsm, Null ); //Your own function */ +/* } */ +/* else */ +/* { */ +/* nsm_free( nsm ); */ +/* nsm = 0; */ +/* } */ +/* } */ +/* } */ +/**************************************************************************/ + +#ifndef _NSM_H +#define _NSM_H + +#define NSM_API_VERSION_MAJOR 1 +#define NSM_API_VERSION_MINOR 0 + +#include +#include +#include +#include +#include +#include + +typedef void * nsm_client_t; +typedef int (nsm_open_callback)( const char *name, const char *display_name, const char *client_id, char **out_msg, void *userdata ); +typedef int (nsm_save_callback)( char **out_msg, void *userdata ); +typedef void (nsm_show_gui_callback)( void *userdata ); +typedef void (nsm_hide_gui_callback)( void *userdata ); +typedef void (nsm_active_callback)( int b, void *userdata ); +typedef void (nsm_session_is_loaded_callback)( void *userdata ); +typedef int (nsm_broadcast_callback)( const char *, lo_message m, void *userdata ); + +#define _NSM() ((struct _nsm_client_t*)nsm) + +#define NSM_EXPORT __attribute__((unused)) static + +/* private parts */ +struct _nsm_client_t +{ + const char *nsm_url; + + lo_server _server; + lo_server_thread _st; + lo_address nsm_addr; + + int nsm_is_active; + char *nsm_client_id; + char *_session_manager_name; + char *_session_manager_features; + + nsm_open_callback *open; + void *open_userdata; + + nsm_save_callback *save; + void *save_userdata; + + nsm_show_gui_callback *show; + void *show_userdata; + + nsm_hide_gui_callback *hide; + void *hide_userdata; + + nsm_active_callback *active; + void *active_userdata; + + nsm_session_is_loaded_callback *session_is_loaded; + void *session_is_loaded_userdata; + + nsm_broadcast_callback *broadcast; + void *broadcast_userdata; +}; + +enum +{ + ERR_OK = 0, + ERR_GENERAL = -1, + ERR_INCOMPATIBLE_API = -2, + ERR_BLACKLISTED = -3, + ERR_LAUNCH_FAILED = -4, + ERR_NO_SUCH_FILE = -5, + ERR_NO_SESSION_OPEN = -6, + ERR_UNSAVED_CHANGES = -7, + ERR_NOT_NOW = -8 +}; + +NSM_EXPORT +int +nsm_is_active ( nsm_client_t *nsm ) +{ + return _NSM()->nsm_is_active; +} + +NSM_EXPORT +const char * +nsm_get_session_manager_name ( nsm_client_t *nsm ) +{ + return _NSM()->_session_manager_name; +} + +NSM_EXPORT +const char * +nsm_get_session_manager_features ( nsm_client_t *nsm ) +{ + return _NSM()->_session_manager_features; +} + +NSM_EXPORT +nsm_client_t * +nsm_new ( void ) +{ + struct _nsm_client_t *nsm = (struct _nsm_client_t*)malloc( sizeof( struct _nsm_client_t ) ); + + nsm->nsm_url = 0; + + nsm->nsm_is_active = 0; + nsm->nsm_client_id = 0; + + nsm->_server = 0; + nsm->_st = 0; + nsm->nsm_addr = 0; + nsm->_session_manager_name = 0; + nsm->_session_manager_features = 0; + + nsm->open = 0; + nsm->save = 0; + nsm->show = 0; + nsm->hide = 0; + nsm->active = 0; + nsm->session_is_loaded = 0; + nsm->broadcast = 0; + + return (nsm_client_t *)nsm; +} + +/*******************************************/ +/* CLIENT TO SERVER INFORMATIONAL MESSAGES */ +/*******************************************/ + +NSM_EXPORT +void +nsm_send_is_dirty ( nsm_client_t *nsm ) +{ + if ( _NSM()->nsm_is_active ) + lo_send_from( _NSM()->nsm_addr, _NSM()->_server, LO_TT_IMMEDIATE, "/nsm/client/is_dirty", "" ); +} + +NSM_EXPORT +void +nsm_send_is_clean ( nsm_client_t *nsm ) +{ + if ( _NSM()->nsm_is_active ) + lo_send_from( _NSM()->nsm_addr, _NSM()->_server, LO_TT_IMMEDIATE, "/nsm/client/is_clean", "" ); +} + +NSM_EXPORT +void +nsm_send_is_shown ( nsm_client_t *nsm ) +{ + if ( _NSM()->nsm_is_active ) + lo_send_from( _NSM()->nsm_addr, _NSM()->_server, LO_TT_IMMEDIATE, "/nsm/client/gui_is_shown", "" ); +} + +NSM_EXPORT +void +nsm_send_is_hidden ( nsm_client_t *nsm ) +{ + if ( _NSM()->nsm_is_active ) + lo_send_from( _NSM()->nsm_addr, _NSM()->_server, LO_TT_IMMEDIATE, "/nsm/client/gui_is_hidden", "" ); +} + +NSM_EXPORT +void +nsm_send_progress ( nsm_client_t *nsm, float p ) +{ + if ( _NSM()->nsm_is_active ) + lo_send_from( _NSM()->nsm_addr, _NSM()->_server, LO_TT_IMMEDIATE, "/nsm/client/progress", "f", p ); +} + +NSM_EXPORT +void +nsm_send_message ( nsm_client_t *nsm, int priority, const char *msg ) +{ + if ( _NSM()->nsm_is_active ) + lo_send_from( _NSM()->nsm_addr, _NSM()->_server, LO_TT_IMMEDIATE, "/nsm/client/message", "is", priority, msg ); +} + +NSM_EXPORT void +nsm_send_announce ( nsm_client_t *nsm, const char *app_name, const char *capabilities, const char *process_name ) +{ + lo_address to = lo_address_new_from_url( _NSM()->nsm_url ); + + if ( ! to ) + { + fprintf( stderr, "NSM: Bad address!" ); + return; + } + + int pid = (int)getpid(); + + lo_send_from( to, _NSM()->_server, LO_TT_IMMEDIATE, "/nsm/server/announce", "sssiii", + app_name, + capabilities, + process_name, + NSM_API_VERSION_MAJOR, + NSM_API_VERSION_MINOR, + pid ); + + lo_address_free( to ); +} + +NSM_EXPORT void +nsm_send_broadcast ( nsm_client_t *nsm, lo_message msg ) +{ + if ( _NSM()->nsm_is_active ) + lo_send_message_from( _NSM()->nsm_addr, _NSM()->_server, "/nsm/server/broadcast", msg ); +} + + + +NSM_EXPORT +void +nsm_check_wait ( nsm_client_t *nsm, int timeout ) +{ + if ( lo_server_wait( _NSM()->_server, timeout ) ) + while ( lo_server_recv_noblock( _NSM()->_server, 0 ) ) {} +} + +NSM_EXPORT +void +nsm_check_nowait (nsm_client_t *nsm ) +{ + nsm_check_wait( nsm, 0 ); +} + + +NSM_EXPORT +void +nsm_thread_start ( nsm_client_t *nsm ) +{ + lo_server_thread_start( _NSM()->_st ); +} + + +NSM_EXPORT +void +nsm_thread_stop ( nsm_client_t *nsm ) +{ + lo_server_thread_stop( _NSM()->_st ); +} + + + +NSM_EXPORT void +nsm_free ( nsm_client_t *nsm ) +{ + if ( _NSM()->_st ) + nsm_thread_stop( nsm ); + + if ( _NSM()->_st ) + lo_server_thread_free( _NSM()->_st ); + else + lo_server_free( _NSM()->_server ); + + lo_address_free(_NSM()->nsm_addr); + free(_NSM()->nsm_client_id); + free(_NSM()->_session_manager_name); + free(_NSM()->_session_manager_features); + + free( _NSM() ); +} + +/*****************/ +/* SET CALLBACKS */ +/*****************/ + +NSM_EXPORT +void +nsm_set_open_callback( nsm_client_t *nsm, nsm_open_callback *open_callback, void *userdata ) +{ + _NSM()->open = open_callback; + _NSM()->open_userdata = userdata; +} + +NSM_EXPORT +void +nsm_set_save_callback( nsm_client_t *nsm, nsm_save_callback *save_callback, void *userdata ) +{ + _NSM()->save = save_callback; + _NSM()->save_userdata = userdata; + +} + +NSM_EXPORT +void +nsm_set_show_callback( nsm_client_t *nsm, nsm_show_gui_callback *show_callback, void *userdata ) +{ + _NSM()->show = show_callback; + _NSM()->show_userdata = userdata; +} + +NSM_EXPORT +void +nsm_set_hide_callback( nsm_client_t *nsm, nsm_hide_gui_callback *hide_callback, void *userdata ) +{ + _NSM()->hide = hide_callback; + _NSM()->hide_userdata = userdata; +} + +NSM_EXPORT +void +nsm_set_active_callback( nsm_client_t *nsm, nsm_active_callback *active_callback, void *userdata ) +{ + _NSM()->active = active_callback; + _NSM()->active_userdata = userdata; +} + +NSM_EXPORT +void +nsm_set_session_is_loaded_callback( nsm_client_t *nsm, nsm_session_is_loaded_callback *session_is_loaded_callback, void *userdata ) +{ + _NSM()->session_is_loaded = session_is_loaded_callback; + _NSM()->session_is_loaded_userdata = userdata; +} + + +NSM_EXPORT +void +nsm_set_broadcast_callback( nsm_client_t *nsm, nsm_broadcast_callback *broadcast_callback, void *userdata ) +{ + _NSM()->broadcast = broadcast_callback; + _NSM()->broadcast_userdata = userdata; +} + + + +/****************/ +/* OSC HANDLERS */ +/****************/ + +#undef OSC_REPLY +#undef OSC_REPLY_ERR + +#define OSC_REPLY( value ) lo_send_from( ((struct _nsm_client_t*)user_data)->nsm_addr, ((struct _nsm_client_t*)user_data)->_server, LO_TT_IMMEDIATE, "/reply", "ss", path, value ) + +#define OSC_REPLY_ERR( errcode, value ) lo_send_from( ((struct _nsm_client_t*)user_data)->nsm_addr, ((struct _nsm_client_t*)user_data)->_server, LO_TT_IMMEDIATE, "/error", "sis", path, errcode, value ) + + +NSM_EXPORT int _nsm_osc_open ( const char *path, const char *types, lo_arg **argv, int argc, lo_message msg, void *user_data ) +{ + (void) types; + (void) argc; + (void) msg; + + char *out_msg = NULL; + + struct _nsm_client_t *nsm = (struct _nsm_client_t*)user_data; + + nsm->nsm_client_id = strdup( &argv[2]->s ); + + if ( ! nsm->open ) + return 0; + + int r = nsm->open( &argv[0]->s, &argv[1]->s, &argv[2]->s, &out_msg, nsm->open_userdata ); + + if ( r ) + OSC_REPLY_ERR( r, ( out_msg ? out_msg : "") ); + else + OSC_REPLY( "OK" ); + + if ( out_msg ) + free( out_msg ); + + return 0; +} + +NSM_EXPORT int _nsm_osc_save ( const char *path, const char *types, lo_arg **argv, int argc, lo_message msg, void *user_data ) +{ + (void) types; + (void) argv; + (void) argc; + (void) msg; + + char *out_msg = NULL; + + struct _nsm_client_t *nsm = (struct _nsm_client_t*)user_data; + + if ( ! nsm->save ) + return 0; + + int r = nsm->save(&out_msg, nsm->save_userdata ); + + if ( r ) + OSC_REPLY_ERR( r, ( out_msg ? out_msg : "") ); + else + OSC_REPLY( "OK" ); + + if ( out_msg ) + free( out_msg ); + + return 0; +} + +NSM_EXPORT int _nsm_osc_announce_reply ( const char *path, const char *types, lo_arg **argv, int argc, lo_message msg, void *user_data ) +{ + (void) path; + (void) types; + (void) argc; + + if ( strcmp( &argv[0]->s, "/nsm/server/announce" ) ) + return -1; + + struct _nsm_client_t *nsm = (struct _nsm_client_t*)user_data; + + fprintf( stderr, "NSM: Successfully registered. NSM says: %s", &argv[1]->s ); + + nsm->nsm_is_active = 1; + nsm->_session_manager_name = strdup( &argv[2]->s ); + nsm->_session_manager_features = strdup( &argv[3]->s ); + nsm->nsm_addr = lo_address_new_from_url( lo_address_get_url( lo_message_get_source( msg ) )); + + if ( nsm->active ) + nsm->active( nsm->nsm_is_active, nsm->active_userdata ); + + return 0; +} + +NSM_EXPORT int _nsm_osc_error ( const char *path, const char *types, lo_arg **argv, int argc, lo_message msg, void *user_data ) +{ + (void) path; + (void) types; + (void) argc; + (void) msg; + + if ( strcmp( &argv[0]->s, "/nsm/server/announce" ) ) + return -1; + + struct _nsm_client_t *nsm = (struct _nsm_client_t*)user_data; + + fprintf( stderr, "NSM: Failed to register with NSM server: %s", &argv[2]->s ); + + nsm->nsm_is_active = 0; + + if ( nsm->active ) + nsm->active( nsm->nsm_is_active, nsm->active_userdata ); + + return 0; +} + +NSM_EXPORT int _nsm_osc_session_is_loaded ( const char *path, const char *types, lo_arg **argv, int argc, lo_message msg, void *user_data ) +{ + (void) path; + (void) types; + (void) argv; + (void) argc; + (void) msg; + + struct _nsm_client_t *nsm = (struct _nsm_client_t*)user_data; + + if ( ! nsm->session_is_loaded ) + return 0; + + nsm->session_is_loaded( nsm->session_is_loaded_userdata ); + + return 0; +} + +NSM_EXPORT int _nsm_osc_show ( const char *path, const char *types, lo_arg **argv, int argc, lo_message msg, void *user_data ) +{ + + struct _nsm_client_t *nsm = (struct _nsm_client_t*)user_data; + + if ( ! nsm->show ) + return 0; + + nsm->show( nsm->show_userdata ); + + return 0; +} + +NSM_EXPORT int _nsm_osc_hide ( const char *path, const char *types, lo_arg **argv, int argc, lo_message msg, void *user_data ) +{ + + struct _nsm_client_t *nsm = (struct _nsm_client_t*)user_data; + + if ( ! nsm->hide ) + return 0; + + nsm->hide( nsm->hide_userdata ); + + return 0; +} + +NSM_EXPORT int _nsm_osc_broadcast ( const char *path, const char *types, lo_arg **argv, int argc, lo_message msg, void *user_data ) +{ + (void) types; + (void) argv; + (void) argc; + + struct _nsm_client_t *nsm = (struct _nsm_client_t*)user_data; + + if ( ! nsm->broadcast ) + return 0; + + return nsm->broadcast( path, msg, nsm->broadcast_userdata ); +} + + + +NSM_EXPORT +int +nsm_init ( nsm_client_t *nsm, const char *nsm_url ) +{ + _NSM()->nsm_url = nsm_url; + + lo_address addr = lo_address_new_from_url( nsm_url ); + int proto = lo_address_get_protocol( addr ); + lo_address_free( addr ); + + _NSM()->_server = lo_server_new_with_proto( NULL, proto, NULL ); + + if ( ! _NSM()->_server ) + return -1; + + lo_server_add_method( _NSM()->_server, "/error", "sis", _nsm_osc_error, _NSM() ); + lo_server_add_method( _NSM()->_server, "/reply", "ssss", _nsm_osc_announce_reply, _NSM() ); + lo_server_add_method( _NSM()->_server, "/nsm/client/open", "sss", _nsm_osc_open, _NSM() ); + lo_server_add_method( _NSM()->_server, "/nsm/client/save", "", _nsm_osc_save, _NSM() ); + lo_server_add_method( _NSM()->_server, "/nsm/client/session_is_loaded", "", _nsm_osc_session_is_loaded, _NSM() ); + lo_server_add_method( _NSM()->_server, "/nsm/client/show_optional_gui", "", _nsm_osc_show, _NSM() ); + lo_server_add_method( _NSM()->_server, "/nsm/client/hide_optional_gui", "", _nsm_osc_hide, _NSM() ); + lo_server_add_method( _NSM()->_server, NULL, NULL, _nsm_osc_broadcast, _NSM() ); + + return 0; +} + + +NSM_EXPORT +int +nsm_init_thread ( nsm_client_t *nsm, const char *nsm_url ) +{ + _NSM()->nsm_url = nsm_url; + + lo_address addr = lo_address_new_from_url( nsm_url ); + int proto = lo_address_get_protocol( addr ); + lo_address_free( addr ); + + _NSM()->_st = lo_server_thread_new_with_proto( NULL, proto, NULL ); + _NSM()->_server = lo_server_thread_get_server( _NSM()->_st ); + + if ( ! _NSM()->_server ) + return -1; + + lo_server_thread_add_method( _NSM()->_st, "/error", "sis", _nsm_osc_error, _NSM() ); + lo_server_thread_add_method( _NSM()->_st, "/reply", "ssss", _nsm_osc_announce_reply, _NSM() ); + lo_server_thread_add_method( _NSM()->_st, "/nsm/client/open", "sss", _nsm_osc_open, _NSM() ); + lo_server_thread_add_method( _NSM()->_st, "/nsm/client/save", "", _nsm_osc_save, _NSM() ); + lo_server_thread_add_method( _NSM()->_st, "/nsm/client/session_is_loaded", "", _nsm_osc_session_is_loaded, _NSM() ); + lo_server_thread_add_method( _NSM()->_st, "/nsm/client/show_optional_gui", "", _nsm_osc_show, _NSM() ); + lo_server_thread_add_method( _NSM()->_st, "/nsm/client/hide_optional_gui", "", _nsm_osc_hide, _NSM() ); + lo_server_thread_add_method( _NSM()->_st, NULL, NULL, _nsm_osc_broadcast, _NSM() ); + + return 0; +} + +#endif /* NSM_H */ diff --git a/programstate.c b/programstate.c new file mode 100644 index 0000000..9841ae6 --- /dev/null +++ b/programstate.c @@ -0,0 +1,248 @@ +//Standard lib +#include +#include +#include +#include +#include +#include +#include + +//Third party +#include "raylib.h" +#include "jRead.h" //included in our source https://www.codeproject.com/Articles/885389/jRead-An-in-place-JSON-Element-Reader +#include "jWrite.h" //included in our source https://www.codeproject.com/Articles/887604/jWrite-A-Really-Simple-JSON-Writer-in-C + +//Our own files +#include "constants.h" +#include "programstate.h" +#include "drawhelper.h" +#include "draw.h" + +#define SAVE_BUFFER_LEN 1024*1024*4 //4 MB to be on the safe side. This is just RAM, not the file size. + +ProgramState programState; //global singleton state. All other files use extern ProgramState programState; + +void setColorPalette(int number) { + + //First set Background to default, in case a palette only works with notes. + //Otherwise the palette can overwrite. + + srand(time(0)); + + programState.colors[VIS_PORTS+0] = (Color){ 45, 50, 57, 255 }; //LSS Background color. The general background, lowest layer. + programState.colors[VIS_PORTS+1] = (Color){ 55, 61, 69, 127 }; //used for note backgrounds + programState.colors[VIS_PORTS+2] = (Color){ 65, 65, 65, 200 }; //e.g. pitch marker + + switch (number) { + case 1: //random notes. Background default + for (int i=0; i= 1. multiplied with time of one frame (0.016s @ 60fps). Factor 3 is the same as bpm fadeout with 120bpm + programState.showConnectedPortnames = true; + programState.includeClientInPortNameDisplay = false; + programState.alwaysShowClock = false; + programState.applicationWindowVisible = true; //for nsm + //.camera is not saved, but we will save the values individually + programState.camera.zoom = 1.0f; + programState.camera.rotation = 0.0f; + programState.cameraCenterOnX = 0; + programState.cameraCenterOnY = 0; + programState.pitchMin = 0+2*12; //Note Drawing Range for all modes + programState.pitchMax = 127-2*12; //Pitch is inclusive. Note Drawing Range for all modes + + //Layer Switches. Also see enum in constants.h + programState.showBackgroundImageLayer = false; //or plain color + programState.showEffectLayer = true; + programState.showSpriteLayer = true; + programState.showDrawMode = true; + + //Layer Modes and Settings + //char * backgroundImagePath; + programState.drawMode = 0; + + setColorPalette(0); + + //For specific modes only + programState.meterbridge_grouping = 1; // 127 / 1 as default -> show all notes individually. 12 would mean show activity in one octave as the same rectangle. pitchmarker is the root note. + + //Images and paths + programState.pathBackgroundImage = ""; //set by load or draw.h. This is a path, not the texture. + + //Not Saved + programState.clockString = malloc (sizeof(char) * 255); //set by jack + programState.guiRedrawNeeded = true; //screen size or drawing configuration changed + programState.instructedToQuit = false; //internal signal for the quit button + programState.guiVisible = false; //Press ESC + programState.bpm = 0.0d; //set by jack + //programState.transportRolling; + programState.modeDescription = ""; // \n for line break. Label to describe a mode. Set by files like draw_port_grids.c etc. + //programState.connectedPortNames #empty + programState.portActivity[VIS_PORTS]; + programState.lockInput = false; //Prevent keypresses while in file open dialog etc. + + //Not saved but provided or changed by NSM or args + programState.name = strdup(programName); + if (nsm) { + programState.nsmDirectory = strdup(filePath); //Our directory in NSM, empty standalone. Don't use for checks, use bool programState.nsm instead + programState.filePath = malloc (sizeof(char) * 4096); //4096 is the max path length in linux + snprintf(programState.filePath, (sizeof(char) * 4096), "%s/%s", filePath, "tgvssave.json"); + mkdir(programState.nsmDirectory, 0755); //let silently fail if already exists. We need the dir to symlink image files. + } + else { + programState.filePath = strdup(filePath); //This is always the direct json save file. + } + loadStateFromFile(); +} + +void loadStateFromFile() { + //call only after initProgramState + if (programState.nsm) { + } + + if (programState.filePath && programState.filePath[0] != '\0') { + char * buffer; + buffer = LoadFileText(programState.filePath); // Load text data from file (read), returns a '\0' terminated string + + + //Begin de-serializing save data + if (buffer) { + + //printf("%s\n", buffer); //print whole json file. + + //A third parameter NULL is for jRead query params and recommended as default + programState.showPitchMarker = (bool)jRead_int(buffer, "{'showPitchMarker'", NULL); + programState.pitchMarkerValue = jRead_int(buffer, "{'pitchMarkerValue'", NULL); + programState.showPortBackground = (bool)jRead_int(buffer, "{'showPortBackground'", NULL); + programState.showPortBackgroundForUnconnected = (bool)jRead_int(buffer, "{'showPortBackgroundForUnconnected'", NULL); + programState.fadeOutMode = jRead_int(buffer, "{'fadeOutMode'", NULL); + programState.fadeOutFactor = jRead_int(buffer, "{'fadeOutFactor'", NULL); + programState.showConnectedPortnames = (bool)jRead_int(buffer, "{'showConnectedPortnames'", NULL); + programState.includeClientInPortNameDisplay = (bool)jRead_int(buffer, "{'includeClientInPortNameDisplay'", NULL); + programState.alwaysShowClock = (bool)jRead_int(buffer, "{'alwaysShowClock'", NULL); + programState.applicationWindowVisible = (bool)jRead_int(buffer, "{'applicationWindowVisible'", NULL); + programState.cameraCenterOnX = jRead_int(buffer, "{'cameraCenterOnX'", NULL); + programState.cameraCenterOnY = jRead_int(buffer, "{'cameraCenterOnY'", NULL); + programState.camera.zoom = (float)jRead_double(buffer, "{'camera.zoom'", NULL); + programState.camera.rotation = (float)jRead_double(buffer, "{'camera.rotation'", NULL); + programState.pitchMin = jRead_int(buffer, "{'pitchMin'", NULL); + programState.pitchMax = jRead_int(buffer, "{'pitchMax'", NULL); + programState.meterbridge_grouping = jRead_int(buffer, "{'meterbridge_grouping'", NULL); + + programState.drawMode = jRead_int(buffer, "{'drawMode'", NULL); + + programState.showBackgroundImageLayer = (bool)jRead_int(buffer, "{'showBackgroundImageLayer'", NULL); + programState.showEffectLayer = (bool)jRead_int(buffer, "{'showEffectLayer'", NULL); + programState.showSpriteLayer = (bool)jRead_int(buffer, "{'showSpriteLayer'", NULL); + programState.showDrawMode = (bool)jRead_int(buffer, "{'showDrawMode'", NULL); + + //int jRead_string( char *pJson, char *pQuery, char *pDest, int destlen, int *queryParams ); + char bgimgpath[4096]; + jRead_string(buffer, "{'pathBackgroundImage'", bgimgpath, 4096 , NULL); + loadBackgroundImage(bgimgpath, false); //sets programState.pathBackgroundImage + + + char colorKey[64]; + for (int i=0; i<19; i++) { + sprintf(colorKey, "{'colors_%i'", i); + //Thanks jRead! we saved the color value as string, because the long-write function does not exist. But luckily it parses everything back during read :). + programState.colors[i] = GetColor(jRead_long(buffer, colorKey, NULL)); + } + + } + else { + printf("Unable to open %s. Starting with default program state. Expected for first run.\n", programState.filePath); + } + } + else { + printf("No filepath present. Not loading anything, every setting is temporary.\n"); + + } +} + +void saveStateToFile() { + //call only after initProgramState + + if (programState.filePath && programState.filePath[0] != '\0') { + char buffer[SAVE_BUFFER_LEN]; + int returnJWCode; + + jwOpen( buffer, SAVE_BUFFER_LEN, JW_OBJECT, JW_PRETTY ); // open root node as object + //jwObj_string( "key", "value" ); + jwObj_int( "showPitchMarker", (int)programState.showPitchMarker ); + jwObj_int( "pitchMarkerValue", programState.pitchMarkerValue ); + jwObj_int( "showPortBackground", (int)programState.showPortBackground ); + jwObj_int( "showPortBackgroundForUnconnected", (int)programState.showPortBackgroundForUnconnected ); + jwObj_int( "fadeOutMode", programState.fadeOutMode ); + jwObj_int( "fadeOutFactor", programState.fadeOutFactor ); + jwObj_int( "showConnectedPortnames", (int)programState.showConnectedPortnames ); + jwObj_int( "includeClientInPortNameDisplay", (int)programState.includeClientInPortNameDisplay ); + jwObj_int( "alwaysShowClock", (int)programState.alwaysShowClock ); + jwObj_int( "applicationWindowVisible", (int)programState.applicationWindowVisible ); + jwObj_int( "cameraCenterOnX", programState.cameraCenterOnX ); + jwObj_int( "cameraCenterOnY", programState.cameraCenterOnY ); + jwObj_double( "camera.zoom", (double)programState.camera.zoom ); + jwObj_double( "camera.rotation", (double)programState.camera.rotation ); + jwObj_int( "pitchMin", programState.pitchMin ); + jwObj_int( "pitchMax", programState.pitchMax ); + jwObj_int( "meterbridge_grouping", programState.meterbridge_grouping ); + + jwObj_int( "drawMode", programState.drawMode ); + + jwObj_int( "showBackgroundImageLayer", (int)programState.showBackgroundImageLayer ); + jwObj_int( "showEffectLayer", (int)programState.showEffectLayer ); + jwObj_int( "showSpriteLayer", (int)programState.showSpriteLayer ); + jwObj_int( "showDrawMode", (int)programState.showDrawMode ); + + jwObj_string( "pathBackgroundImage", programState.pathBackgroundImage ); + + + char colorKey[64]; + char colorValue[256]; + for (int i=0; i<19; i++) { + sprintf(colorKey, "colors_%i", i); + sprintf(colorValue, "%li", ColorToInt(programState.colors[i])); + jwObj_string( colorKey, colorValue ); + } + + returnJWCode = jwClose(); + + SaveFileText(programState.filePath, buffer); // Save text data to file (write), string must be '\0' terminated + } +} + diff --git a/programstate.h b/programstate.h new file mode 100644 index 0000000..dabb374 --- /dev/null +++ b/programstate.h @@ -0,0 +1,79 @@ +#ifndef PROGRAMSTATE_H +#define PROGRAMSTATE_H + +#include "constants.h" + +//Singleton. This is also saved and loaded. See main.c +typedef struct { + + bool nsm; //under nsm or not + + //Saved + ///////////////////// + bool guiVisible; + bool showPitchMarker; + int pitchMarkerValue; + bool showPortBackground; + bool showPortBackgroundForUnconnected; + int fadeOutMode; + int fadeOutFactor; + bool showConnectedPortnames; + bool includeClientInPortNameDisplay; + bool alwaysShowClock; + bool applicationWindowVisible; + int cameraCenterOnX; + int cameraCenterOnY; + int pitchMin; //Note Drawing Range for all modes + int pitchMax; //Note Drawing Range for all modes + + //Layer Switches + + bool showBackgroundImageLayer; //or plain color + bool showEffectLayer; + bool showSpriteLayer; + bool showDrawMode; + bool showForegroundSpritesLayer; + bool showForegroundEffectsLayer; + + //Layer Modes and Settings + //char * backgroundImagePath; + + int drawMode; //Vertical, Grids... + + Color colors[VIS_PORTS+3]; + + //For specific modes only + int meterbridge_grouping; // 127 / 1 as default -> show all notes individually. 12 would mean show activity in one octave as the same rectangle. pitchmarker is the root note. + + //Images and paths + char * pathBackgroundImage; //in nsm this is always background.png , standalone it is an absolute file path + + //Not Saved + ///////////////////// + bool guiRedrawNeeded; + bool instructedToQuit; + bool transportRolling; + double bpm; + char* clockString; + const char* connectedPortNames[VIS_PORTS]; + const char * modeDescription; //48 chars per line.\n for line break. Label to describe a mode. Set by files like draw_port_grids.c etc. + int portActivity[VIS_PORTS]; //0 means no activity, any other number is the number of current note-ons + bool lockInput; //Prevent keypresses while in file open dialog etc. + Camera2D camera; + + //Not saved but provided by NSM or argc + ///////////////////// + char * name; + char * nsmDirectory; //Our directory in NSM, empty standalone. Don't use for checks, use bool programState.nsm instead + char * filePath; //This is always the direct json save file. There is only one filePath per session. We do not provide "reload" or "open" + +} ProgramState; + + +void initProgramState(bool nsm, const char * filePath, const char * programName); +void loadStateFromFile(); +void saveStateToFile(); +void setColorPalette(int number); + + +#endif // not defined PROGRAMSTATE_H diff --git a/raygui.h b/raygui.h new file mode 100644 index 0000000..b36c4ae --- /dev/null +++ b/raygui.h @@ -0,0 +1,3734 @@ +/******************************************************************************************* +* +* raygui v2.8 - A simple and easy-to-use immediate-mode gui library +* +* DESCRIPTION: +* +* raygui is a tools-dev-focused immediate-mode-gui library based on raylib but also +* available as a standalone library, as long as input and drawing functions are provided. +* +* Controls provided: +* +* # Container/separators Controls +* - WindowBox +* - GroupBox +* - Line +* - Panel +* +* # Basic Controls +* - Label +* - Button +* - LabelButton --> Label +* - ImageButton --> Button +* - ImageButtonEx --> Button +* - Toggle +* - ToggleGroup --> Toggle +* - CheckBox +* - ComboBox +* - DropdownBox +* - TextBox +* - TextBoxMulti +* - ValueBox --> TextBox +* - Spinner --> Button, ValueBox +* - Slider +* - SliderBar --> Slider +* - ProgressBar +* - StatusBar +* - ScrollBar +* - ScrollPanel +* - DummyRec +* - Grid +* +* # Advance Controls +* - ListView +* - ColorPicker --> ColorPanel, ColorBarHue +* - MessageBox --> Window, Label, Button +* - TextInputBox --> Window, Label, TextBox, Button +* +* It also provides a set of functions for styling the controls based on its properties (size, color). +* +* CONFIGURATION: +* +* #define RAYGUI_IMPLEMENTATION +* Generates the implementation of the library into the included file. +* If not defined, the library is in header only mode and can be included in other headers +* or source files without problems. But only ONE file should hold the implementation. +* +* #define RAYGUI_STATIC (defined by default) +* The generated implementation will stay private inside implementation file and all +* internal symbols and functions will only be visible inside that file. +* +* #define RAYGUI_STANDALONE +* Avoid raylib.h header inclusion in this file. Data types defined on raylib are defined +* internally in the library and input management and drawing functions must be provided by +* the user (check library implementation for further details). +* +* #define RAYGUI_SUPPORT_ICONS +* Includes riconsdata.h header defining a set of 128 icons (binary format) to be used on +* multiple controls and following raygui styles +* +* +* VERSIONS HISTORY: +* 2.8 (03-May-2020) Centralized rectangles drawing to GuiDrawRectangle() +* 2.7 (20-Feb-2020) Added possible tooltips API +* 2.6 (09-Sep-2019) ADDED: GuiTextInputBox() +* REDESIGNED: GuiListView*(), GuiDropdownBox(), GuiSlider*(), GuiProgressBar(), GuiMessageBox() +* REVIEWED: GuiTextBox(), GuiSpinner(), GuiValueBox(), GuiLoadStyle() +* Replaced property INNER_PADDING by TEXT_PADDING, renamed some properties +* Added 8 new custom styles ready to use +* Multiple minor tweaks and bugs corrected +* 2.5 (28-May-2019) Implemented extended GuiTextBox(), GuiValueBox(), GuiSpinner() +* 2.3 (29-Apr-2019) Added rIcons auxiliar library and support for it, multiple controls reviewed +* Refactor all controls drawing mechanism to use control state +* 2.2 (05-Feb-2019) Added GuiScrollBar(), GuiScrollPanel(), reviewed GuiListView(), removed Gui*Ex() controls +* 2.1 (26-Dec-2018) Redesign of GuiCheckBox(), GuiComboBox(), GuiDropdownBox(), GuiToggleGroup() > Use combined text string +* Complete redesign of style system (breaking change) +* 2.0 (08-Nov-2018) Support controls guiLock and custom fonts, reviewed GuiComboBox(), GuiListView()... +* 1.9 (09-Oct-2018) Controls review: GuiGrid(), GuiTextBox(), GuiTextBoxMulti(), GuiValueBox()... +* 1.8 (01-May-2018) Lot of rework and redesign to align with rGuiStyler and rGuiLayout +* 1.5 (21-Jun-2017) Working in an improved styles system +* 1.4 (15-Jun-2017) Rewritten all GUI functions (removed useless ones) +* 1.3 (12-Jun-2017) Redesigned styles system +* 1.1 (01-Jun-2017) Complete review of the library +* 1.0 (07-Jun-2016) Converted to header-only by Ramon Santamaria. +* 0.9 (07-Mar-2016) Reviewed and tested by Albert Martos, Ian Eito, Sergio Martinez and Ramon Santamaria. +* 0.8 (27-Aug-2015) Initial release. Implemented by Kevin Gato, Daniel Nicolás and Ramon Santamaria. +* +* CONTRIBUTORS: +* Ramon Santamaria: Supervision, review, redesign, update and maintenance... +* Vlad Adrian: Complete rewrite of GuiTextBox() to support extended features (2019) +* Sergio Martinez: Review, testing (2015) and redesign of multiple controls (2018) +* Adria Arranz: Testing and Implementation of additional controls (2018) +* Jordi Jorba: Testing and Implementation of additional controls (2018) +* Albert Martos: Review and testing of the library (2015) +* Ian Eito: Review and testing of the library (2015) +* Kevin Gato: Initial implementation of basic components (2014) +* Daniel Nicolas: Initial implementation of basic components (2014) +* +* +* LICENSE: zlib/libpng +* +* Copyright (c) 2014-2020 Ramon Santamaria (@raysan5) +* +* This software is provided "as-is", without any express or implied warranty. In no event +* will the authors be held liable for any damages arising from the use of this software. +* +* Permission is granted to anyone to use this software for any purpose, including commercial +* applications, and to alter it and redistribute it freely, subject to the following restrictions: +* +* 1. The origin of this software must not be misrepresented; you must not claim that you +* wrote the original software. If you use this software in a product, an acknowledgment +* in the product documentation would be appreciated but is not required. +* +* 2. Altered source versions must be plainly marked as such, and must not be misrepresented +* as being the original software. +* +* 3. This notice may not be removed or altered from any source distribution. +* +**********************************************************************************************/ + +#ifndef RAYGUI_H +#define RAYGUI_H + +#define RAYGUI_VERSION "2.6-dev" + +#if !defined(RAYGUI_STANDALONE) + #include "raylib.h" +#endif + +// Define functions scope to be used internally (static) or externally (extern) to the module including this file +#if defined(RAYGUI_STATIC) + #define RAYGUIDEF static // Functions just visible to module including this file +#else + #ifdef __cplusplus + #define RAYGUIDEF extern "C" // Functions visible from other files (no name mangling of functions in C++) + #else + // NOTE: By default any function declared in a C file is extern + #define RAYGUIDEF extern // Functions visible from other files + #endif +#endif + +#if defined(_WIN32) + #if defined(BUILD_LIBTYPE_SHARED) + #define RAYGUIDEF __declspec(dllexport) // We are building raygui as a Win32 shared library (.dll). + #elif defined(USE_LIBTYPE_SHARED) + #define RAYGUIDEF __declspec(dllimport) // We are using raygui as a Win32 shared library (.dll) + #endif +#endif + + +#if !defined(RAYGUI_MALLOC) && !defined(RAYGUI_CALLOC) && !defined(RAYGUI_FREE) + #include // Required for: malloc(), calloc(), free() +#endif + +// Allow custom memory allocators +#ifndef RAYGUI_MALLOC + #define RAYGUI_MALLOC(sz) malloc(sz) +#endif +#ifndef RAYGUI_CALLOC + #define RAYGUI_CALLOC(n,sz) calloc(n,sz) +#endif +#ifndef RAYGUI_FREE + #define RAYGUI_FREE(p) free(p) +#endif + +//---------------------------------------------------------------------------------- +// Defines and Macros +//---------------------------------------------------------------------------------- +#define NUM_CONTROLS 16 // Number of standard controls +#define NUM_PROPS_DEFAULT 16 // Number of standard properties +#define NUM_PROPS_EXTENDED 8 // Number of extended properties + +#define TEXTEDIT_CURSOR_BLINK_FRAMES 20 // Text edit controls cursor blink timming + +//---------------------------------------------------------------------------------- +// Types and Structures Definition +// NOTE: Some types are required for RAYGUI_STANDALONE usage +//---------------------------------------------------------------------------------- +#if defined(RAYGUI_STANDALONE) + #ifndef __cplusplus + // Boolean type + #ifndef true + typedef enum { false, true } bool; + #endif + #endif + + // Vector2 type + typedef struct Vector2 { + float x; + float y; + } Vector2; + + // Vector3 type + typedef struct Vector3 { + float x; + float y; + float z; + } Vector3; + + // Color type, RGBA (32bit) + typedef struct Color { + unsigned char r; + unsigned char g; + unsigned char b; + unsigned char a; + } Color; + + // Rectangle type + typedef struct Rectangle { + float x; + float y; + float width; + float height; + } Rectangle; + + // TODO: Texture2D type is very coupled to raylib, mostly required by GuiImageButton() + // It should be redesigned to be provided by user + typedef struct Texture2D { + unsigned int id; // OpenGL texture id + int width; // Texture base width + int height; // Texture base height + int mipmaps; // Mipmap levels, 1 by default + int format; // Data format (PixelFormat type) + } Texture2D; + + // Font character info + typedef struct CharInfo CharInfo; + + // TODO: Font type is very coupled to raylib, mostly required by GuiLoadStyle() + // It should be redesigned to be provided by user + typedef struct Font { + int baseSize; // Base size (default chars height) + int charsCount; // Number of characters + Texture2D texture; // Characters texture atlas + Rectangle *recs; // Characters rectangles in texture + CharInfo *chars; // Characters info data + } Font; +#endif + +// Style property +typedef struct GuiStyleProp { + unsigned short controlId; + unsigned short propertyId; + int propertyValue; +} GuiStyleProp; + +// Gui control state +typedef enum { + GUI_STATE_NORMAL = 0, + GUI_STATE_FOCUSED, + GUI_STATE_PRESSED, + GUI_STATE_DISABLED, +} GuiControlState; + +// Gui control text alignment +typedef enum { + GUI_TEXT_ALIGN_LEFT = 0, + GUI_TEXT_ALIGN_CENTER, + GUI_TEXT_ALIGN_RIGHT, +} GuiTextAlignment; + +// Gui controls +typedef enum { + DEFAULT = 0, + LABEL, // LABELBUTTON + BUTTON, // IMAGEBUTTON + TOGGLE, // TOGGLEGROUP + SLIDER, // SLIDERBAR + PROGRESSBAR, + CHECKBOX, + COMBOBOX, + DROPDOWNBOX, + TEXTBOX, // TEXTBOXMULTI + VALUEBOX, + SPINNER, + LISTVIEW, + COLORPICKER, + SCROLLBAR, + STATUSBAR +} GuiControl; + +// Gui base properties for every control +typedef enum { + BORDER_COLOR_NORMAL = 0, + BASE_COLOR_NORMAL, + TEXT_COLOR_NORMAL, + BORDER_COLOR_FOCUSED, + BASE_COLOR_FOCUSED, + TEXT_COLOR_FOCUSED, + BORDER_COLOR_PRESSED, + BASE_COLOR_PRESSED, + TEXT_COLOR_PRESSED, + BORDER_COLOR_DISABLED, + BASE_COLOR_DISABLED, + TEXT_COLOR_DISABLED, + BORDER_WIDTH, + TEXT_PADDING, + TEXT_ALIGNMENT, + RESERVED +} GuiControlProperty; + +// Gui extended properties depend on control +// NOTE: We reserve a fixed size of additional properties per control + +// DEFAULT properties +typedef enum { + TEXT_SIZE = 16, + TEXT_SPACING, + LINE_COLOR, + BACKGROUND_COLOR, +} GuiDefaultProperty; + +// Label +//typedef enum { } GuiLabelProperty; + +// Button +//typedef enum { } GuiButtonProperty; + +// Toggle / ToggleGroup +typedef enum { + GROUP_PADDING = 16, +} GuiToggleProperty; + +// Slider / SliderBar +typedef enum { + SLIDER_WIDTH = 16, + SLIDER_PADDING +} GuiSliderProperty; + +// ProgressBar +typedef enum { + PROGRESS_PADDING = 16, +} GuiProgressBarProperty; + +// CheckBox +typedef enum { + CHECK_PADDING = 16 +} GuiCheckBoxProperty; + +// ComboBox +typedef enum { + COMBO_BUTTON_WIDTH = 16, + COMBO_BUTTON_PADDING +} GuiComboBoxProperty; + +// DropdownBox +typedef enum { + ARROW_PADDING = 16, + DROPDOWN_ITEMS_PADDING +} GuiDropdownBoxProperty; + +// TextBox / TextBoxMulti / ValueBox / Spinner +typedef enum { + TEXT_INNER_PADDING = 16, + TEXT_LINES_PADDING, + COLOR_SELECTED_FG, + COLOR_SELECTED_BG +} GuiTextBoxProperty; + +// Spinner +typedef enum { + SPIN_BUTTON_WIDTH = 16, + SPIN_BUTTON_PADDING, +} GuiSpinnerProperty; + +// ScrollBar +typedef enum { + ARROWS_SIZE = 16, + ARROWS_VISIBLE, + SCROLL_SLIDER_PADDING, + SCROLL_SLIDER_SIZE, + SCROLL_PADDING, + SCROLL_SPEED, +} GuiScrollBarProperty; + +// ScrollBar side +typedef enum { + SCROLLBAR_LEFT_SIDE = 0, + SCROLLBAR_RIGHT_SIDE +} GuiScrollBarSide; + +// ListView +typedef enum { + LIST_ITEMS_HEIGHT = 16, + LIST_ITEMS_PADDING, + SCROLLBAR_WIDTH, + SCROLLBAR_SIDE, +} GuiListViewProperty; + +// ColorPicker +typedef enum { + COLOR_SELECTOR_SIZE = 16, + HUEBAR_WIDTH, // Right hue bar width + HUEBAR_PADDING, // Right hue bar separation from panel + HUEBAR_SELECTOR_HEIGHT, // Right hue bar selector height + HUEBAR_SELECTOR_OVERFLOW // Right hue bar selector overflow +} GuiColorPickerProperty; + +//---------------------------------------------------------------------------------- +// Global Variables Definition +//---------------------------------------------------------------------------------- +// ... + +//---------------------------------------------------------------------------------- +// Module Functions Declaration +//---------------------------------------------------------------------------------- + +// State modification functions +RAYGUIDEF void GuiEnable(void); // Enable gui controls (global state) +RAYGUIDEF void GuiDisable(void); // Disable gui controls (global state) +RAYGUIDEF void GuiLock(void); // Lock gui controls (global state) +RAYGUIDEF void GuiUnlock(void); // Unlock gui controls (global state) +RAYGUIDEF void GuiFade(float alpha); // Set gui controls alpha (global state), alpha goes from 0.0f to 1.0f +RAYGUIDEF void GuiSetState(int state); // Set gui state (global state) +RAYGUIDEF int GuiGetState(void); // Get gui state (global state) + +// Font set/get functions +RAYGUIDEF void GuiSetFont(Font font); // Set gui custom font (global state) +RAYGUIDEF Font GuiGetFont(void); // Get gui custom font (global state) + +// Style set/get functions +RAYGUIDEF void GuiSetStyle(int control, int property, int value); // Set one style property +RAYGUIDEF int GuiGetStyle(int control, int property); // Get one style property + +// Tooltips set functions +RAYGUIDEF void GuiEnableTooltip(void); // Enable gui tooltips +RAYGUIDEF void GuiDisableTooltip(void); // Disable gui tooltips +RAYGUIDEF void GuiSetTooltip(const char *tooltip); // Set current tooltip for display +RAYGUIDEF void GuiClearTooltip(void); // Clear any tooltip registered + +// Container/separator controls, useful for controls organization +RAYGUIDEF bool GuiWindowBox(Rectangle bounds, const char *title); // Window Box control, shows a window that can be closed +RAYGUIDEF void GuiGroupBox(Rectangle bounds, const char *text); // Group Box control with text name +RAYGUIDEF void GuiLine(Rectangle bounds, const char *text); // Line separator control, could contain text +RAYGUIDEF void GuiPanel(Rectangle bounds); // Panel control, useful to group controls +RAYGUIDEF Rectangle GuiScrollPanel(Rectangle bounds, Rectangle content, Vector2 *scroll); // Scroll Panel control + +// Basic controls set +RAYGUIDEF void GuiLabel(Rectangle bounds, const char *text); // Label control, shows text +RAYGUIDEF bool GuiButton(Rectangle bounds, const char *text); // Button control, returns true when clicked +RAYGUIDEF bool GuiLabelButton(Rectangle bounds, const char *text); // Label button control, show true when clicked +RAYGUIDEF bool GuiImageButton(Rectangle bounds, const char *text, Texture2D texture); // Image button control, returns true when clicked +RAYGUIDEF bool GuiImageButtonEx(Rectangle bounds, const char *text, Texture2D texture, Rectangle texSource); // Image button extended control, returns true when clicked +RAYGUIDEF bool GuiToggle(Rectangle bounds, const char *text, bool active); // Toggle Button control, returns true when active +RAYGUIDEF int GuiToggleGroup(Rectangle bounds, const char *text, int active); // Toggle Group control, returns active toggle index +RAYGUIDEF bool GuiCheckBox(Rectangle bounds, const char *text, bool checked); // Check Box control, returns true when active +RAYGUIDEF int GuiComboBox(Rectangle bounds, const char *text, int active); // Combo Box control, returns selected item index +RAYGUIDEF bool GuiDropdownBox(Rectangle bounds, const char *text, int *active, bool editMode); // Dropdown Box control, returns selected item +RAYGUIDEF bool GuiSpinner(Rectangle bounds, const char *text, int *value, int minValue, int maxValue, bool editMode); // Spinner control, returns selected value +RAYGUIDEF bool GuiValueBox(Rectangle bounds, const char *text, int *value, int minValue, int maxValue, bool editMode); // Value Box control, updates input text with numbers +RAYGUIDEF bool GuiTextBox(Rectangle bounds, char *text, int textSize, bool editMode); // Text Box control, updates input text +RAYGUIDEF bool GuiTextBoxMulti(Rectangle bounds, char *text, int textSize, bool editMode); // Text Box control with multiple lines +RAYGUIDEF float GuiSlider(Rectangle bounds, const char *textLeft, const char *textRight, float value, float minValue, float maxValue); // Slider control, returns selected value +RAYGUIDEF float GuiSliderBar(Rectangle bounds, const char *textLeft, const char *textRight, float value, float minValue, float maxValue); // Slider Bar control, returns selected value +RAYGUIDEF float GuiProgressBar(Rectangle bounds, const char *textLeft, const char *textRight, float value, float minValue, float maxValue); // Progress Bar control, shows current progress value +RAYGUIDEF void GuiStatusBar(Rectangle bounds, const char *text); // Status Bar control, shows info text +RAYGUIDEF void GuiDummyRec(Rectangle bounds, const char *text); // Dummy control for placeholders +RAYGUIDEF int GuiScrollBar(Rectangle bounds, int value, int minValue, int maxValue); // Scroll Bar control +RAYGUIDEF Vector2 GuiGrid(Rectangle bounds, float spacing, int subdivs); // Grid control + +// Advance controls set +RAYGUIDEF int GuiListView(Rectangle bounds, const char *text, int *scrollIndex, int active); // List View control, returns selected list item index +RAYGUIDEF int GuiListViewEx(Rectangle bounds, const char **text, int count, int *focus, int *scrollIndex, int active); // List View with extended parameters +RAYGUIDEF int GuiMessageBox(Rectangle bounds, const char *title, const char *message, const char *buttons); // Message Box control, displays a message +RAYGUIDEF int GuiTextInputBox(Rectangle bounds, const char *title, const char *message, const char *buttons, char *text); // Text Input Box control, ask for text +RAYGUIDEF Color GuiColorPicker(Rectangle bounds, Color color); // Color Picker control (multiple color controls) +RAYGUIDEF Color GuiColorPanel(Rectangle bounds, Color color); // Color Panel control +RAYGUIDEF float GuiColorBarAlpha(Rectangle bounds, float alpha); // Color Bar Alpha control +RAYGUIDEF float GuiColorBarHue(Rectangle bounds, float value); // Color Bar Hue control + +// Styles loading functions +RAYGUIDEF void GuiLoadStyle(const char *fileName); // Load style file (.rgs) +RAYGUIDEF void GuiLoadStyleDefault(void); // Load style default over global style + +/* +typedef GuiStyle (unsigned int *) +RAYGUIDEF GuiStyle LoadGuiStyle(const char *fileName); // Load style from file (.rgs) +RAYGUIDEF void UnloadGuiStyle(GuiStyle style); // Unload style +*/ + +RAYGUIDEF const char *GuiIconText(int iconId, const char *text); // Get text with icon id prepended (if supported) + +#if defined(RAYGUI_SUPPORT_ICONS) +// Gui icons functionality +RAYGUIDEF void GuiDrawIcon(int iconId, Vector2 position, int pixelSize, Color color); + +RAYGUIDEF unsigned int *GuiGetIcons(void); // Get full icons data pointer +RAYGUIDEF unsigned int *GuiGetIconData(int iconId); // Get icon bit data +RAYGUIDEF void GuiSetIconData(int iconId, unsigned int *data); // Set icon bit data + +RAYGUIDEF void GuiSetIconPixel(int iconId, int x, int y); // Set icon pixel value +RAYGUIDEF void GuiClearIconPixel(int iconId, int x, int y); // Clear icon pixel value +RAYGUIDEF bool GuiCheckIconPixel(int iconId, int x, int y); // Check icon pixel value +#endif + +#endif // RAYGUI_H + + +/*********************************************************************************** +* +* RAYGUI IMPLEMENTATION +* +************************************************************************************/ + +#if defined(RAYGUI_IMPLEMENTATION) + +#if defined(RAYGUI_SUPPORT_ICONS) + #define RICONS_IMPLEMENTATION + #include "ricons.h" // Required for: raygui icons data +#endif + +#include // Required for: FILE, fopen(), fclose(), fprintf(), feof(), fscanf(), vsprintf() +#include // Required for: strlen() on GuiTextBox() +#include // Required for: roundf() on GuiColorPicker() + +#if defined(RAYGUI_STANDALONE) + #include // Required for: va_list, va_start(), vfprintf(), va_end() +#endif + +#ifdef __cplusplus + #define RAYGUI_CLITERAL(name) name +#else + #define RAYGUI_CLITERAL(name) (name) +#endif + +//---------------------------------------------------------------------------------- +// Defines and Macros +//---------------------------------------------------------------------------------- +//... + +//---------------------------------------------------------------------------------- +// Types and Structures Definition +//---------------------------------------------------------------------------------- +// Gui control property style color element +typedef enum { BORDER = 0, BASE, TEXT, OTHER } GuiPropertyElement; + +//---------------------------------------------------------------------------------- +// Global Variables Definition +//---------------------------------------------------------------------------------- +static GuiControlState guiState = GUI_STATE_NORMAL; + +static Font guiFont = { 0 }; // Gui current font (WARNING: highly coupled to raylib) +static bool guiLocked = false; // Gui lock state (no inputs processed) +static float guiAlpha = 1.0f; // Gui element transpacency on drawing + +// Global gui style array (allocated on data segment by default) +// NOTE: In raygui we manage a single int array with all the possible style properties. +// When a new style is loaded, it loads over the global style... but default gui style +// could always be recovered with GuiLoadStyleDefault() +static unsigned int guiStyle[NUM_CONTROLS*(NUM_PROPS_DEFAULT + NUM_PROPS_EXTENDED)] = { 0 }; +static bool guiStyleLoaded = false; // Style loaded flag for lazy style initialization + +// Tooltips required variables +static const char *guiTooltip = NULL; // Gui tooltip currently active (user provided) +static bool guiTooltipEnabled = true; // Gui tooltips enabled + +//---------------------------------------------------------------------------------- +// Standalone Mode Functions Declaration +// +// NOTE: raygui depend on some raylib input and drawing functions +// To use raygui as standalone library, below functions must be defined by the user +//---------------------------------------------------------------------------------- +#if defined(RAYGUI_STANDALONE) + +#define KEY_RIGHT 262 +#define KEY_LEFT 263 +#define KEY_DOWN 264 +#define KEY_UP 265 +#define KEY_BACKSPACE 259 +#define KEY_ENTER 257 + +#define MOUSE_LEFT_BUTTON 0 + +// Input required functions +//------------------------------------------------------------------------------- +static Vector2 GetMousePosition(void); +static int GetMouseWheelMove(void); +static bool IsMouseButtonDown(int button); +static bool IsMouseButtonPressed(int button); +static bool IsMouseButtonReleased(int button); + +static bool IsKeyDown(int key); +static bool IsKeyPressed(int key); +static int GetKeyPressed(void); // -- GuiTextBox(), GuiTextBoxMulti(), GuiValueBox() +//------------------------------------------------------------------------------- + +// Drawing required functions +//------------------------------------------------------------------------------- +static void DrawRectangle(int x, int y, int width, int height, Color color); // -- GuiDrawRectangle(), GuiDrawIcon() + +static void DrawRectangleGradientEx(Rectangle rec, Color col1, Color col2, Color col3, Color col4); // -- GuiColorPicker() +static void DrawTriangle(Vector2 v1, Vector2 v2, Vector2 v3, Color color); // -- GuiDropdownBox(), GuiScrollBar() +static void DrawTextureRec(Texture2D texture, Rectangle sourceRec, Vector2 position, Color tint); // -- GuiImageButtonEx() + +static void DrawTextRec(Font font, const char *text, Rectangle rec, float fontSize, float spacing, bool wordWrap, Color tint); // -- GuiTextBoxMulti() +//------------------------------------------------------------------------------- + +// Text required functions +//------------------------------------------------------------------------------- +static Font GetFontDefault(void); // -- GuiLoadStyleDefault() +static Vector2 MeasureTextEx(Font font, const char *text, float fontSize, float spacing); // -- GetTextWidth(), GuiTextBoxMulti() +static void DrawTextEx(Font font, const char *text, Vector2 position, float fontSize, float spacing, Color tint); // -- GuiDrawText() + +static Font LoadFontEx(const char *fileName, int fontSize, int *fontChars, int charsCount); // -- GuiLoadStyle() +static char *LoadText(const char *fileName); // -- GuiLoadStyle() +static const char *GetDirectoryPath(const char *filePath); // -- GuiLoadStyle() +//------------------------------------------------------------------------------- + +// raylib functions already implemented in raygui +//------------------------------------------------------------------------------- +static Color GetColor(int hexValue); // Returns a Color struct from hexadecimal value +static int ColorToInt(Color color); // Returns hexadecimal value for a Color +static Color Fade(Color color, float alpha); // Color fade-in or fade-out, alpha goes from 0.0f to 1.0f +static bool CheckCollisionPointRec(Vector2 point, Rectangle rec); // Check if point is inside rectangle +static const char *TextFormat(const char *text, ...); // Formatting of text with variables to 'embed' +static const char **TextSplit(const char *text, char delimiter, int *count); // Split text into multiple strings +static int TextToInteger(const char *text); // Get integer value from text + +static void DrawRectangleGradientV(int posX, int posY, int width, int height, Color color1, Color color2); // Draw rectangle vertical gradient +//------------------------------------------------------------------------------- + +#endif // RAYGUI_STANDALONE + +//---------------------------------------------------------------------------------- +// Module specific Functions Declaration +//---------------------------------------------------------------------------------- +static int GetTextWidth(const char *text); // Gui get text width using default font +static Rectangle GetTextBounds(int control, Rectangle bounds); // Get text bounds considering control bounds +static const char *GetTextIcon(const char *text, int *iconId); // Get text icon if provided and move text cursor + +static void GuiDrawText(const char *text, Rectangle bounds, int alignment, Color tint); // Gui draw text using default font +static void GuiDrawRectangle(Rectangle rec, int borderWidth, Color borderColor, Color color); // Gui draw rectangle using default raygui style +static void GuiDrawTooltip(Rectangle bounds); // Draw tooltip relatively to bounds + +static const char **GuiTextSplit(const char *text, int *count, int *textRow); // Split controls text into multiple strings +static Vector3 ConvertHSVtoRGB(Vector3 hsv); // Convert color data from HSV to RGB +static Vector3 ConvertRGBtoHSV(Vector3 rgb); // Convert color data from RGB to HSV + +//---------------------------------------------------------------------------------- +// Gui Setup Functions Definition +//---------------------------------------------------------------------------------- +// Enable gui global state +void GuiEnable(void) { guiState = GUI_STATE_NORMAL; } + +// Disable gui global state +void GuiDisable(void) { guiState = GUI_STATE_DISABLED; } + +// Lock gui global state +void GuiLock(void) { guiLocked = true; } + +// Unlock gui global state +void GuiUnlock(void) { guiLocked = false; } + +// Set gui controls alpha global state +void GuiFade(float alpha) +{ + if (alpha < 0.0f) alpha = 0.0f; + else if (alpha > 1.0f) alpha = 1.0f; + + guiAlpha = alpha; +} + +// Set gui state (global state) +void GuiSetState(int state) { guiState = (GuiControlState)state; } + +// Get gui state (global state) +int GuiGetState(void) { return guiState; } + +// Set custom gui font +// NOTE: Font loading/unloading is external to raygui +void GuiSetFont(Font font) +{ + if (font.texture.id > 0) + { + // NOTE: If we try to setup a font but default style has not been + // lazily loaded before, it will be overwritten, so we need to force + // default style loading first + if (!guiStyleLoaded) GuiLoadStyleDefault(); + + guiFont = font; + GuiSetStyle(DEFAULT, TEXT_SIZE, font.baseSize); + } +} + +// Get custom gui font +Font GuiGetFont(void) +{ + return guiFont; +} + +// Set control style property value +void GuiSetStyle(int control, int property, int value) +{ + if (!guiStyleLoaded) GuiLoadStyleDefault(); + guiStyle[control*(NUM_PROPS_DEFAULT + NUM_PROPS_EXTENDED) + property] = value; + + // Default properties are propagated to all controls + if ((control == 0) && (property < NUM_PROPS_DEFAULT)) + { + for (int i = 1; i < NUM_CONTROLS; i++) guiStyle[i*(NUM_PROPS_DEFAULT + NUM_PROPS_EXTENDED) + property] = value; + } +} + +// Get control style property value +int GuiGetStyle(int control, int property) +{ + if (!guiStyleLoaded) GuiLoadStyleDefault(); + return guiStyle[control*(NUM_PROPS_DEFAULT + NUM_PROPS_EXTENDED) + property]; +} + +// Enable gui tooltips +void GuiEnableTooltip(void) { guiTooltipEnabled = true; } + +// Disable gui tooltips +void GuiDisableTooltip(void) { guiTooltipEnabled = false; } + +// Set current tooltip for display +void GuiSetTooltip(const char *tooltip) { guiTooltip = tooltip; } + +// Clear any tooltip registered +void GuiClearTooltip(void) { guiTooltip = NULL; } + + +//---------------------------------------------------------------------------------- +// Gui Controls Functions Definition +//---------------------------------------------------------------------------------- + +// Window Box control +bool GuiWindowBox(Rectangle bounds, const char *title) +{ + // NOTE: This define is also used by GuiMessageBox() and GuiTextInputBox() + #define WINDOW_STATUSBAR_HEIGHT 22 + + //GuiControlState state = guiState; + bool clicked = false; + + int statusBarHeight = WINDOW_STATUSBAR_HEIGHT + 2*GuiGetStyle(STATUSBAR, BORDER_WIDTH); + statusBarHeight += (statusBarHeight%2); + + Rectangle statusBar = { bounds.x, bounds.y, bounds.width, statusBarHeight }; + if (bounds.height < statusBarHeight*2) bounds.height = statusBarHeight*2; + + Rectangle windowPanel = { bounds.x, bounds.y + statusBarHeight - 1, bounds.width, bounds.height - statusBarHeight }; + Rectangle closeButtonRec = { statusBar.x + statusBar.width - GuiGetStyle(STATUSBAR, BORDER_WIDTH) - 20, + statusBar.y + statusBarHeight/2 - 18/2, 18, 18 }; + + // Update control + //-------------------------------------------------------------------- + // NOTE: Logic is directly managed by button + //-------------------------------------------------------------------- + + // Draw control + //-------------------------------------------------------------------- + GuiStatusBar(statusBar, title); // Draw window header as status bar + GuiPanel(windowPanel); // Draw window base + + // Draw window close button + int tempBorderWidth = GuiGetStyle(BUTTON, BORDER_WIDTH); + int tempTextAlignment = GuiGetStyle(BUTTON, TEXT_ALIGNMENT); + GuiSetStyle(BUTTON, BORDER_WIDTH, 1); + GuiSetStyle(BUTTON, TEXT_ALIGNMENT, GUI_TEXT_ALIGN_CENTER); +#if defined(RAYGUI_SUPPORT_ICONS) + clicked = GuiButton(closeButtonRec, GuiIconText(RICON_CROSS_SMALL, NULL)); +#else + clicked = GuiButton(closeButtonRec, "x"); +#endif + GuiSetStyle(BUTTON, BORDER_WIDTH, tempBorderWidth); + GuiSetStyle(BUTTON, TEXT_ALIGNMENT, tempTextAlignment); + //-------------------------------------------------------------------- + + return clicked; +} + +// Group Box control with text name +void GuiGroupBox(Rectangle bounds, const char *text) +{ + #define GROUPBOX_LINE_THICK 1 + #define GROUPBOX_TEXT_PADDING 10 + + GuiControlState state = guiState; + + // Draw control + //-------------------------------------------------------------------- + GuiDrawRectangle(RAYGUI_CLITERAL(Rectangle){ bounds.x, bounds.y, GROUPBOX_LINE_THICK, bounds.height }, 0, BLANK, Fade(GetColor(GuiGetStyle(DEFAULT, (state == GUI_STATE_DISABLED)? BORDER_COLOR_DISABLED : LINE_COLOR)), guiAlpha)); + GuiDrawRectangle(RAYGUI_CLITERAL(Rectangle){ bounds.x, bounds.y + bounds.height - 1, bounds.width, GROUPBOX_LINE_THICK }, 0, BLANK, Fade(GetColor(GuiGetStyle(DEFAULT, (state == GUI_STATE_DISABLED)? BORDER_COLOR_DISABLED : LINE_COLOR)), guiAlpha)); + GuiDrawRectangle(RAYGUI_CLITERAL(Rectangle){ bounds.x + bounds.width - 1, bounds.y, GROUPBOX_LINE_THICK, bounds.height }, 0, BLANK, Fade(GetColor(GuiGetStyle(DEFAULT, (state == GUI_STATE_DISABLED)? BORDER_COLOR_DISABLED : LINE_COLOR)), guiAlpha)); + + GuiLine(RAYGUI_CLITERAL(Rectangle){ bounds.x, bounds.y, bounds.width, 1 }, text); + //-------------------------------------------------------------------- +} + +// Line control +void GuiLine(Rectangle bounds, const char *text) +{ + #define LINE_TEXT_PADDING 10 + + GuiControlState state = guiState; + + Color color = Fade(GetColor(GuiGetStyle(DEFAULT, (state == GUI_STATE_DISABLED)? BORDER_COLOR_DISABLED : LINE_COLOR)), guiAlpha); + + // Draw control + //-------------------------------------------------------------------- + if (text == NULL) GuiDrawRectangle(RAYGUI_CLITERAL(Rectangle){ bounds.x, bounds.y + bounds.height/2, bounds.width, 1 }, 0, BLANK, color); + else + { + Rectangle textBounds = { 0 }; + textBounds.width = GetTextWidth(text); // TODO: Consider text icon + textBounds.height = GuiGetStyle(DEFAULT, TEXT_SIZE); + textBounds.x = bounds.x + LINE_TEXT_PADDING; + textBounds.y = bounds.y - GuiGetStyle(DEFAULT, TEXT_SIZE)/2; + + // Draw line with embedded text label: "--- text --------------" + GuiDrawRectangle(RAYGUI_CLITERAL(Rectangle){ bounds.x, bounds.y, LINE_TEXT_PADDING - 2, 1 }, 0, BLANK, color); + GuiLabel(textBounds, text); + GuiDrawRectangle(RAYGUI_CLITERAL(Rectangle){ bounds.x + LINE_TEXT_PADDING + textBounds.width + 4, bounds.y, bounds.width - textBounds.width - LINE_TEXT_PADDING - 4, 1 }, 0, BLANK, color); + } + //-------------------------------------------------------------------- +} + +// Panel control +void GuiPanel(Rectangle bounds) +{ + #define PANEL_BORDER_WIDTH 1 + + GuiControlState state = guiState; + + // Draw control + //-------------------------------------------------------------------- + GuiDrawRectangle(bounds, PANEL_BORDER_WIDTH, Fade(GetColor(GuiGetStyle(DEFAULT, (state == GUI_STATE_DISABLED)? BORDER_COLOR_DISABLED: LINE_COLOR)), guiAlpha), + Fade(GetColor(GuiGetStyle(DEFAULT, (state == GUI_STATE_DISABLED)? BASE_COLOR_DISABLED : BACKGROUND_COLOR)), guiAlpha)); + //-------------------------------------------------------------------- +} + +// Scroll Panel control +Rectangle GuiScrollPanel(Rectangle bounds, Rectangle content, Vector2 *scroll) +{ + GuiControlState state = guiState; + + Vector2 scrollPos = { 0.0f, 0.0f }; + if (scroll != NULL) scrollPos = *scroll; + + bool hasHorizontalScrollBar = (content.width > bounds.width - 2*GuiGetStyle(DEFAULT, BORDER_WIDTH))? true : false; + bool hasVerticalScrollBar = (content.height > bounds.height - 2*GuiGetStyle(DEFAULT, BORDER_WIDTH))? true : false; + + // Recheck to account for the other scrollbar being visible + if (!hasHorizontalScrollBar) hasHorizontalScrollBar = (hasVerticalScrollBar && (content.width > (bounds.width - 2*GuiGetStyle(DEFAULT, BORDER_WIDTH) - GuiGetStyle(LISTVIEW, SCROLLBAR_WIDTH))))? true : false; + if (!hasVerticalScrollBar) hasVerticalScrollBar = (hasHorizontalScrollBar && (content.height > (bounds.height - 2*GuiGetStyle(DEFAULT, BORDER_WIDTH) - GuiGetStyle(LISTVIEW, SCROLLBAR_WIDTH))))? true : false; + + const int horizontalScrollBarWidth = hasHorizontalScrollBar? GuiGetStyle(LISTVIEW, SCROLLBAR_WIDTH) : 0; + const int verticalScrollBarWidth = hasVerticalScrollBar? GuiGetStyle(LISTVIEW, SCROLLBAR_WIDTH) : 0; + const Rectangle horizontalScrollBar = { (float)((GuiGetStyle(LISTVIEW, SCROLLBAR_SIDE) == SCROLLBAR_LEFT_SIDE)? (float)bounds.x + verticalScrollBarWidth : (float)bounds.x) + GuiGetStyle(DEFAULT, BORDER_WIDTH), (float)bounds.y + bounds.height - horizontalScrollBarWidth - GuiGetStyle(DEFAULT, BORDER_WIDTH), (float)bounds.width - verticalScrollBarWidth - 2*GuiGetStyle(DEFAULT, BORDER_WIDTH), (float)horizontalScrollBarWidth }; + const Rectangle verticalScrollBar = { (float)((GuiGetStyle(LISTVIEW, SCROLLBAR_SIDE) == SCROLLBAR_LEFT_SIDE)? (float)bounds.x + GuiGetStyle(DEFAULT, BORDER_WIDTH) : (float)bounds.x + bounds.width - verticalScrollBarWidth - GuiGetStyle(DEFAULT, BORDER_WIDTH)), (float)bounds.y + GuiGetStyle(DEFAULT, BORDER_WIDTH), (float)verticalScrollBarWidth, (float)bounds.height - horizontalScrollBarWidth - 2*GuiGetStyle(DEFAULT, BORDER_WIDTH) }; + + // Calculate view area (area without the scrollbars) + Rectangle view = (GuiGetStyle(LISTVIEW, SCROLLBAR_SIDE) == SCROLLBAR_LEFT_SIDE)? + RAYGUI_CLITERAL(Rectangle){ bounds.x + verticalScrollBarWidth + GuiGetStyle(DEFAULT, BORDER_WIDTH), bounds.y + GuiGetStyle(DEFAULT, BORDER_WIDTH), bounds.width - 2*GuiGetStyle(DEFAULT, BORDER_WIDTH) - verticalScrollBarWidth, bounds.height - 2*GuiGetStyle(DEFAULT, BORDER_WIDTH) - horizontalScrollBarWidth } : + RAYGUI_CLITERAL(Rectangle){ bounds.x + GuiGetStyle(DEFAULT, BORDER_WIDTH), bounds.y + GuiGetStyle(DEFAULT, BORDER_WIDTH), bounds.width - 2*GuiGetStyle(DEFAULT, BORDER_WIDTH) - verticalScrollBarWidth, bounds.height - 2*GuiGetStyle(DEFAULT, BORDER_WIDTH) - horizontalScrollBarWidth }; + + // Clip view area to the actual content size + if (view.width > content.width) view.width = content.width; + if (view.height > content.height) view.height = content.height; + + // TODO: Review! + const int horizontalMin = hasHorizontalScrollBar? ((GuiGetStyle(LISTVIEW, SCROLLBAR_SIDE) == SCROLLBAR_LEFT_SIDE)? -verticalScrollBarWidth : 0) - GuiGetStyle(DEFAULT, BORDER_WIDTH) : ((GuiGetStyle(LISTVIEW, SCROLLBAR_SIDE) == SCROLLBAR_LEFT_SIDE)? -verticalScrollBarWidth : 0) - GuiGetStyle(DEFAULT, BORDER_WIDTH); + const int horizontalMax = hasHorizontalScrollBar? content.width - bounds.width + verticalScrollBarWidth + GuiGetStyle(DEFAULT, BORDER_WIDTH) - ((GuiGetStyle(LISTVIEW, SCROLLBAR_SIDE) == SCROLLBAR_LEFT_SIDE)? verticalScrollBarWidth : 0) : -GuiGetStyle(DEFAULT, BORDER_WIDTH); + const int verticalMin = hasVerticalScrollBar? -GuiGetStyle(DEFAULT, BORDER_WIDTH) : -GuiGetStyle(DEFAULT, BORDER_WIDTH); + const int verticalMax = hasVerticalScrollBar? content.height - bounds.height + horizontalScrollBarWidth + GuiGetStyle(DEFAULT, BORDER_WIDTH) : -GuiGetStyle(DEFAULT, BORDER_WIDTH); + + // Update control + //-------------------------------------------------------------------- + if ((state != GUI_STATE_DISABLED) && !guiLocked) + { + Vector2 mousePoint = GetMousePosition(); + + // Check button state + if (CheckCollisionPointRec(mousePoint, bounds)) + { + if (IsMouseButtonDown(MOUSE_LEFT_BUTTON)) state = GUI_STATE_PRESSED; + else state = GUI_STATE_FOCUSED; + + if (hasHorizontalScrollBar) + { + if (IsKeyDown(KEY_RIGHT)) scrollPos.x -= GuiGetStyle(SCROLLBAR, SCROLL_SPEED); + if (IsKeyDown(KEY_LEFT)) scrollPos.x += GuiGetStyle(SCROLLBAR, SCROLL_SPEED); + } + + if (hasVerticalScrollBar) + { + if (IsKeyDown(KEY_DOWN)) scrollPos.y -= GuiGetStyle(SCROLLBAR, SCROLL_SPEED); + if (IsKeyDown(KEY_UP)) scrollPos.y += GuiGetStyle(SCROLLBAR, SCROLL_SPEED); + } + + scrollPos.y += GetMouseWheelMove()*20; + } + } + + // Normalize scroll values + if (scrollPos.x > -horizontalMin) scrollPos.x = -horizontalMin; + if (scrollPos.x < -horizontalMax) scrollPos.x = -horizontalMax; + if (scrollPos.y > -verticalMin) scrollPos.y = -verticalMin; + if (scrollPos.y < -verticalMax) scrollPos.y = -verticalMax; + //-------------------------------------------------------------------- + + // Draw control + //-------------------------------------------------------------------- + GuiDrawRectangle(bounds, 0, BLANK, GetColor(GuiGetStyle(DEFAULT, BACKGROUND_COLOR))); // Draw background + + // Save size of the scrollbar slider + const int slider = GuiGetStyle(SCROLLBAR, SCROLL_SLIDER_SIZE); + + // Draw horizontal scrollbar if visible + if (hasHorizontalScrollBar) + { + // Change scrollbar slider size to show the diff in size between the content width and the widget width + GuiSetStyle(SCROLLBAR, SCROLL_SLIDER_SIZE, ((bounds.width - 2*GuiGetStyle(DEFAULT, BORDER_WIDTH) - verticalScrollBarWidth)/content.width)*(bounds.width - 2*GuiGetStyle(DEFAULT, BORDER_WIDTH) - verticalScrollBarWidth)); + scrollPos.x = -GuiScrollBar(horizontalScrollBar, -scrollPos.x, horizontalMin, horizontalMax); + } + + // Draw vertical scrollbar if visible + if (hasVerticalScrollBar) + { + // Change scrollbar slider size to show the diff in size between the content height and the widget height + GuiSetStyle(SCROLLBAR, SCROLL_SLIDER_SIZE, ((bounds.height - 2*GuiGetStyle(DEFAULT, BORDER_WIDTH) - horizontalScrollBarWidth)/content.height)* (bounds.height - 2*GuiGetStyle(DEFAULT, BORDER_WIDTH) - horizontalScrollBarWidth)); + scrollPos.y = -GuiScrollBar(verticalScrollBar, -scrollPos.y, verticalMin, verticalMax); + } + + // Draw detail corner rectangle if both scroll bars are visible + if (hasHorizontalScrollBar && hasVerticalScrollBar) + { + // TODO: Consider scroll bars side + Rectangle corner = { horizontalScrollBar.x + horizontalScrollBar.width + 2, verticalScrollBar.y + verticalScrollBar.height + 2, horizontalScrollBarWidth - 4, verticalScrollBarWidth - 4 }; + GuiDrawRectangle(corner, 0, BLANK, Fade(GetColor(GuiGetStyle(LISTVIEW, TEXT + (state*3))), guiAlpha)); + } + + // Draw scrollbar lines depending on current state + GuiDrawRectangle(bounds, GuiGetStyle(DEFAULT, BORDER_WIDTH), Fade(GetColor(GuiGetStyle(LISTVIEW, (float)BORDER + (state*3))), guiAlpha), BLANK); + + // Set scrollbar slider size back to the way it was before + GuiSetStyle(SCROLLBAR, SCROLL_SLIDER_SIZE, slider); + //-------------------------------------------------------------------- + + if (scroll != NULL) *scroll = scrollPos; + + return view; +} + +// Label control +void GuiLabel(Rectangle bounds, const char *text) +{ + GuiControlState state = guiState; + + // Update control + //-------------------------------------------------------------------- + // ... + //-------------------------------------------------------------------- + + // Draw control + //-------------------------------------------------------------------- + GuiDrawText(text, GetTextBounds(LABEL, bounds), GuiGetStyle(LABEL, TEXT_ALIGNMENT), Fade(GetColor(GuiGetStyle(LABEL, (state == GUI_STATE_DISABLED)? TEXT_COLOR_DISABLED : TEXT_COLOR_NORMAL)), guiAlpha)); + //-------------------------------------------------------------------- +} + +// Label control with Color +void GuiLabelColor(Rectangle bounds, const char *text, Color color) +{ + GuiControlState state = guiState; + + // Update control + //-------------------------------------------------------------------- + // ... + //-------------------------------------------------------------------- + + // Draw control + //-------------------------------------------------------------------- + GuiDrawText(text, GetTextBounds(LABEL, bounds), GuiGetStyle(LABEL, TEXT_ALIGNMENT), Fade(color, guiAlpha)); + //-------------------------------------------------------------------- +} + +// Button control, returns true when clicked +bool GuiButton(Rectangle bounds, const char *text) +{ + GuiControlState state = guiState; + bool pressed = false; + + // Update control + //-------------------------------------------------------------------- + if ((state != GUI_STATE_DISABLED) && !guiLocked) + { + Vector2 mousePoint = GetMousePosition(); + + // Check button state + if (CheckCollisionPointRec(mousePoint, bounds)) + { + if (IsMouseButtonDown(MOUSE_LEFT_BUTTON)) state = GUI_STATE_PRESSED; + else state = GUI_STATE_FOCUSED; + + if (IsMouseButtonReleased(MOUSE_LEFT_BUTTON)) pressed = true; + } + } + //-------------------------------------------------------------------- + + // Draw control + //-------------------------------------------------------------------- + GuiDrawRectangle(bounds, GuiGetStyle(BUTTON, BORDER_WIDTH), Fade(GetColor(GuiGetStyle(BUTTON, BORDER + (state*3))), guiAlpha), Fade(GetColor(GuiGetStyle(BUTTON, BASE + (state*3))), guiAlpha)); + GuiDrawText(text, GetTextBounds(BUTTON, bounds), GuiGetStyle(BUTTON, TEXT_ALIGNMENT), Fade(GetColor(GuiGetStyle(BUTTON, TEXT + (state*3))), guiAlpha)); + //------------------------------------------------------------------ + + return pressed; +} + +// Label button control +bool GuiLabelButton(Rectangle bounds, const char *text) +{ + GuiControlState state = guiState; + bool pressed = false; + + // NOTE: We force bounds.width to be all text + int textWidth = MeasureTextEx(guiFont, text, GuiGetStyle(DEFAULT, TEXT_SIZE), GuiGetStyle(DEFAULT, TEXT_SPACING)).x; + if (bounds.width < textWidth) bounds.width = textWidth; + + // Update control + //-------------------------------------------------------------------- + if ((state != GUI_STATE_DISABLED) && !guiLocked) + { + Vector2 mousePoint = GetMousePosition(); + + // Check checkbox state + if (CheckCollisionPointRec(mousePoint, bounds)) + { + if (IsMouseButtonDown(MOUSE_LEFT_BUTTON)) state = GUI_STATE_PRESSED; + else state = GUI_STATE_FOCUSED; + + if (IsMouseButtonReleased(MOUSE_LEFT_BUTTON)) pressed = true; + } + } + //-------------------------------------------------------------------- + + // Draw control + //-------------------------------------------------------------------- + GuiDrawText(text, GetTextBounds(LABEL, bounds), GuiGetStyle(LABEL, TEXT_ALIGNMENT), Fade(GetColor(GuiGetStyle(LABEL, TEXT + (state*3))), guiAlpha)); + //-------------------------------------------------------------------- + + return pressed; +} + +// Image button control, returns true when clicked +bool GuiImageButton(Rectangle bounds, const char *text, Texture2D texture) +{ + return GuiImageButtonEx(bounds, text, texture, RAYGUI_CLITERAL(Rectangle){ 0, 0, (float)texture.width, (float)texture.height }); +} + +// Image button control, returns true when clicked +bool GuiImageButtonEx(Rectangle bounds, const char *text, Texture2D texture, Rectangle texSource) +{ + GuiControlState state = guiState; + bool clicked = false; + + // Update control + //-------------------------------------------------------------------- + if ((state != GUI_STATE_DISABLED) && !guiLocked) + { + Vector2 mousePoint = GetMousePosition(); + + // Check button state + if (CheckCollisionPointRec(mousePoint, bounds)) + { + if (IsMouseButtonDown(MOUSE_LEFT_BUTTON)) state = GUI_STATE_PRESSED; + else if (IsMouseButtonReleased(MOUSE_LEFT_BUTTON)) clicked = true; + else state = GUI_STATE_FOCUSED; + } + } + //-------------------------------------------------------------------- + + // Draw control + //-------------------------------------------------------------------- + GuiDrawRectangle(bounds, GuiGetStyle(BUTTON, BORDER_WIDTH), Fade(GetColor(GuiGetStyle(BUTTON, BORDER + (state*3))), guiAlpha), Fade(GetColor(GuiGetStyle(BUTTON, BASE + (state*3))), guiAlpha)); + + if (text != NULL) GuiDrawText(text, GetTextBounds(BUTTON, bounds), GuiGetStyle(BUTTON, TEXT_ALIGNMENT), Fade(GetColor(GuiGetStyle(BUTTON, TEXT + (state*3))), guiAlpha)); + if (texture.id > 0) DrawTextureRec(texture, texSource, RAYGUI_CLITERAL(Vector2){ bounds.x + bounds.width/2 - texSource.width/2, bounds.y + bounds.height/2 - texSource.height/2 }, Fade(GetColor(GuiGetStyle(BUTTON, TEXT + (state*3))), guiAlpha)); + //------------------------------------------------------------------ + + return clicked; +} + +// Toggle Button control, returns true when active +bool GuiToggle(Rectangle bounds, const char *text, bool active) +{ + GuiControlState state = guiState; + + // Update control + //-------------------------------------------------------------------- + if ((state != GUI_STATE_DISABLED) && !guiLocked) + { + Vector2 mousePoint = GetMousePosition(); + + // Check toggle button state + if (CheckCollisionPointRec(mousePoint, bounds)) + { + if (IsMouseButtonDown(MOUSE_LEFT_BUTTON)) state = GUI_STATE_PRESSED; + else if (IsMouseButtonReleased(MOUSE_LEFT_BUTTON)) + { + state = GUI_STATE_NORMAL; + active = !active; + } + else state = GUI_STATE_FOCUSED; + } + } + //-------------------------------------------------------------------- + + // Draw control + //-------------------------------------------------------------------- + if (state == GUI_STATE_NORMAL) + { + GuiDrawRectangle(bounds, GuiGetStyle(TOGGLE, BORDER_WIDTH), Fade(GetColor(GuiGetStyle(TOGGLE, (active? BORDER_COLOR_PRESSED : (BORDER + state*3)))), guiAlpha), Fade(GetColor(GuiGetStyle(TOGGLE, (active? BASE_COLOR_PRESSED : (BASE + state*3)))), guiAlpha)); + GuiDrawText(text, GetTextBounds(TOGGLE, bounds), GuiGetStyle(TOGGLE, TEXT_ALIGNMENT), Fade(GetColor(GuiGetStyle(TOGGLE, (active? TEXT_COLOR_PRESSED : (TEXT + state*3)))), guiAlpha)); + } + else + { + GuiDrawRectangle(bounds, GuiGetStyle(TOGGLE, BORDER_WIDTH), Fade(GetColor(GuiGetStyle(TOGGLE, BORDER + state*3)), guiAlpha), Fade(GetColor(GuiGetStyle(TOGGLE, BASE + state*3)), guiAlpha)); + GuiDrawText(text, GetTextBounds(TOGGLE, bounds), GuiGetStyle(TOGGLE, TEXT_ALIGNMENT), Fade(GetColor(GuiGetStyle(TOGGLE, TEXT + state*3)), guiAlpha)); + } + //-------------------------------------------------------------------- + + return active; +} + +// Toggle Group control, returns toggled button index +int GuiToggleGroup(Rectangle bounds, const char *text, int active) +{ + #if !defined(TOGGLEGROUP_MAX_ELEMENTS) + #define TOGGLEGROUP_MAX_ELEMENTS 32 + #endif + + float initBoundsX = bounds.x; + + // Get substrings items from text (items pointers) + int rows[TOGGLEGROUP_MAX_ELEMENTS] = { 0 }; + int itemsCount = 0; + const char **items = GuiTextSplit(text, &itemsCount, rows); + + int prevRow = rows[0]; + + for (int i = 0; i < itemsCount; i++) + { + if (prevRow != rows[i]) + { + bounds.x = initBoundsX; + bounds.y += (bounds.height + GuiGetStyle(TOGGLE, GROUP_PADDING)); + prevRow = rows[i]; + } + + if (i == active) GuiToggle(bounds, items[i], true); + else if (GuiToggle(bounds, items[i], false) == true) active = i; + + bounds.x += (bounds.width + GuiGetStyle(TOGGLE, GROUP_PADDING)); + } + + return active; +} + +// Check Box control, returns true when active +bool GuiCheckBox(Rectangle bounds, const char *text, bool checked) +{ + GuiControlState state = guiState; + + Rectangle textBounds = { 0 }; + + if (text != NULL) + { + textBounds.width = GetTextWidth(text); + textBounds.height = GuiGetStyle(DEFAULT, TEXT_SIZE); + textBounds.x = bounds.x + bounds.width + GuiGetStyle(CHECKBOX, TEXT_PADDING); + textBounds.y = bounds.y + bounds.height/2 - GuiGetStyle(DEFAULT, TEXT_SIZE)/2; + if (GuiGetStyle(CHECKBOX, TEXT_ALIGNMENT) == GUI_TEXT_ALIGN_LEFT) textBounds.x = bounds.x - textBounds.width - GuiGetStyle(CHECKBOX, TEXT_PADDING); + } + + // Update control + //-------------------------------------------------------------------- + if ((state != GUI_STATE_DISABLED) && !guiLocked) + { + Vector2 mousePoint = GetMousePosition(); + + Rectangle totalBounds = { + (GuiGetStyle(CHECKBOX, TEXT_ALIGNMENT) == GUI_TEXT_ALIGN_LEFT)? textBounds.x : bounds.x, + bounds.y, + bounds.width + textBounds.width + GuiGetStyle(CHECKBOX, TEXT_PADDING), + bounds.height, + }; + + // Check checkbox state + if (CheckCollisionPointRec(mousePoint, totalBounds)) + { + if (IsMouseButtonDown(MOUSE_LEFT_BUTTON)) state = GUI_STATE_PRESSED; + else state = GUI_STATE_FOCUSED; + + if (IsMouseButtonReleased(MOUSE_LEFT_BUTTON)) checked = !checked; + } + } + //-------------------------------------------------------------------- + + // Draw control + //-------------------------------------------------------------------- + GuiDrawRectangle(bounds, GuiGetStyle(CHECKBOX, BORDER_WIDTH), Fade(GetColor(GuiGetStyle(CHECKBOX, BORDER + (state*3))), guiAlpha), BLANK); + + if (checked) + { + Rectangle check = { bounds.x + GuiGetStyle(CHECKBOX, BORDER_WIDTH) + GuiGetStyle(CHECKBOX, CHECK_PADDING), + bounds.y + GuiGetStyle(CHECKBOX, BORDER_WIDTH) + GuiGetStyle(CHECKBOX, CHECK_PADDING), + bounds.width - 2*(GuiGetStyle(CHECKBOX, BORDER_WIDTH) + GuiGetStyle(CHECKBOX, CHECK_PADDING)), + bounds.height - 2*(GuiGetStyle(CHECKBOX, BORDER_WIDTH) + GuiGetStyle(CHECKBOX, CHECK_PADDING)) }; + GuiDrawRectangle(check, 0, BLANK, Fade(GetColor(GuiGetStyle(CHECKBOX, TEXT + state*3)), guiAlpha)); + } + + if (text != NULL) GuiDrawText(text, textBounds, (GuiGetStyle(CHECKBOX, TEXT_ALIGNMENT) == GUI_TEXT_ALIGN_RIGHT)? GUI_TEXT_ALIGN_LEFT : GUI_TEXT_ALIGN_RIGHT, Fade(GetColor(GuiGetStyle(LABEL, TEXT + (state*3))), guiAlpha)); + //-------------------------------------------------------------------- + + return checked; +} + +// Combo Box control, returns selected item index +int GuiComboBox(Rectangle bounds, const char *text, int active) +{ + GuiControlState state = guiState; + + bounds.width -= (GuiGetStyle(COMBOBOX, COMBO_BUTTON_WIDTH) + GuiGetStyle(COMBOBOX, COMBO_BUTTON_PADDING)); + + Rectangle selector = { (float)bounds.x + bounds.width + GuiGetStyle(COMBOBOX, COMBO_BUTTON_PADDING), + (float)bounds.y, (float)GuiGetStyle(COMBOBOX, COMBO_BUTTON_WIDTH), (float)bounds.height }; + + // Get substrings items from text (items pointers, lengths and count) + int itemsCount = 0; + const char **items = GuiTextSplit(text, &itemsCount, NULL); + + if (active < 0) active = 0; + else if (active > itemsCount - 1) active = itemsCount - 1; + + // Update control + //-------------------------------------------------------------------- + if ((state != GUI_STATE_DISABLED) && !guiLocked && (itemsCount > 1)) + { + Vector2 mousePoint = GetMousePosition(); + + if (CheckCollisionPointRec(mousePoint, bounds) || + CheckCollisionPointRec(mousePoint, selector)) + { + if (IsMouseButtonPressed(MOUSE_LEFT_BUTTON)) + { + active += 1; + if (active >= itemsCount) active = 0; + } + + if (IsMouseButtonDown(MOUSE_LEFT_BUTTON)) state = GUI_STATE_PRESSED; + else state = GUI_STATE_FOCUSED; + } + } + //-------------------------------------------------------------------- + + // Draw control + //-------------------------------------------------------------------- + // Draw combo box main + GuiDrawRectangle(bounds, GuiGetStyle(COMBOBOX, BORDER_WIDTH), Fade(GetColor(GuiGetStyle(COMBOBOX, BORDER + (state*3))), guiAlpha), Fade(GetColor(GuiGetStyle(COMBOBOX, BASE + (state*3))), guiAlpha)); + GuiDrawText(items[active], GetTextBounds(COMBOBOX, bounds), GuiGetStyle(COMBOBOX, TEXT_ALIGNMENT), Fade(GetColor(GuiGetStyle(COMBOBOX, TEXT + (state*3))), guiAlpha)); + + // Draw selector using a custom button + // NOTE: BORDER_WIDTH and TEXT_ALIGNMENT forced values + int tempBorderWidth = GuiGetStyle(BUTTON, BORDER_WIDTH); + int tempTextAlign = GuiGetStyle(BUTTON, TEXT_ALIGNMENT); + GuiSetStyle(BUTTON, BORDER_WIDTH, 1); + GuiSetStyle(BUTTON, TEXT_ALIGNMENT, GUI_TEXT_ALIGN_CENTER); + + GuiButton(selector, TextFormat("%i/%i", active + 1, itemsCount)); + + GuiSetStyle(BUTTON, TEXT_ALIGNMENT, tempTextAlign); + GuiSetStyle(BUTTON, BORDER_WIDTH, tempBorderWidth); + //-------------------------------------------------------------------- + + return active; +} + +// Dropdown Box control +// NOTE: Returns mouse click +bool GuiDropdownBox(Rectangle bounds, const char *text, int *active, bool editMode) +{ + GuiControlState state = guiState; + int itemSelected = *active; + int itemFocused = -1; + + // Get substrings items from text (items pointers, lengths and count) + int itemsCount = 0; + const char **items = GuiTextSplit(text, &itemsCount, NULL); + + Rectangle boundsOpen = bounds; + boundsOpen.height = (itemsCount + 1)*(bounds.height + GuiGetStyle(DROPDOWNBOX, DROPDOWN_ITEMS_PADDING)); + + Rectangle itemBounds = bounds; + + bool pressed = false; // Check mouse button pressed + + // Update control + //-------------------------------------------------------------------- + if ((state != GUI_STATE_DISABLED) && !guiLocked && (itemsCount > 1)) + { + Vector2 mousePoint = GetMousePosition(); + + if (editMode) + { + state = GUI_STATE_PRESSED; + + // Check if mouse has been pressed or released outside limits + if (!CheckCollisionPointRec(mousePoint, boundsOpen)) + { + if (IsMouseButtonPressed(MOUSE_LEFT_BUTTON) || IsMouseButtonReleased(MOUSE_LEFT_BUTTON)) pressed = true; + } + + // Check if already selected item has been pressed again + if (CheckCollisionPointRec(mousePoint, bounds) && IsMouseButtonPressed(MOUSE_LEFT_BUTTON)) pressed = true; + + // Check focused and selected item + for (int i = 0; i < itemsCount; i++) + { + // Update item rectangle y position for next item + itemBounds.y += (bounds.height + GuiGetStyle(DROPDOWNBOX, DROPDOWN_ITEMS_PADDING)); + + if (CheckCollisionPointRec(mousePoint, itemBounds)) + { + itemFocused = i; + if (IsMouseButtonReleased(MOUSE_LEFT_BUTTON)) + { + itemSelected = i; + pressed = true; // Item selected, change to editMode = false + } + break; + } + } + + itemBounds = bounds; + } + else + { + if (CheckCollisionPointRec(mousePoint, bounds)) + { + if (IsMouseButtonPressed(MOUSE_LEFT_BUTTON)) + { + pressed = true; + state = GUI_STATE_PRESSED; + } + else state = GUI_STATE_FOCUSED; + } + } + } + //-------------------------------------------------------------------- + + // Draw control + //-------------------------------------------------------------------- + if (editMode) GuiPanel(boundsOpen); + + GuiDrawRectangle(bounds, GuiGetStyle(DROPDOWNBOX, BORDER_WIDTH), Fade(GetColor(GuiGetStyle(DROPDOWNBOX, BORDER + state*3)), guiAlpha), Fade(GetColor(GuiGetStyle(DROPDOWNBOX, BASE + state*3)), guiAlpha)); + GuiDrawText(items[itemSelected], GetTextBounds(DEFAULT, bounds), GuiGetStyle(DROPDOWNBOX, TEXT_ALIGNMENT), Fade(GetColor(GuiGetStyle(DROPDOWNBOX, TEXT + state*3)), guiAlpha)); + + if (editMode) + { + // Draw visible items + for (int i = 0; i < itemsCount; i++) + { + // Update item rectangle y position for next item + itemBounds.y += (bounds.height + GuiGetStyle(DROPDOWNBOX, DROPDOWN_ITEMS_PADDING)); + + if (i == itemSelected) + { + GuiDrawRectangle(itemBounds, GuiGetStyle(DROPDOWNBOX, BORDER_WIDTH), Fade(GetColor(GuiGetStyle(DROPDOWNBOX, BORDER_COLOR_PRESSED)), guiAlpha), Fade(GetColor(GuiGetStyle(DROPDOWNBOX, BASE_COLOR_PRESSED)), guiAlpha)); + GuiDrawText(items[i], GetTextBounds(DEFAULT, itemBounds), GuiGetStyle(DROPDOWNBOX, TEXT_ALIGNMENT), Fade(GetColor(GuiGetStyle(DROPDOWNBOX, TEXT_COLOR_PRESSED)), guiAlpha)); + } + else if (i == itemFocused) + { + GuiDrawRectangle(itemBounds, GuiGetStyle(DROPDOWNBOX, BORDER_WIDTH), Fade(GetColor(GuiGetStyle(DROPDOWNBOX, BORDER_COLOR_FOCUSED)), guiAlpha), Fade(GetColor(GuiGetStyle(DROPDOWNBOX, BASE_COLOR_FOCUSED)), guiAlpha)); + GuiDrawText(items[i], GetTextBounds(DEFAULT, itemBounds), GuiGetStyle(DROPDOWNBOX, TEXT_ALIGNMENT), Fade(GetColor(GuiGetStyle(DROPDOWNBOX, TEXT_COLOR_FOCUSED)), guiAlpha)); + } + else GuiDrawText(items[i], GetTextBounds(DEFAULT, itemBounds), GuiGetStyle(DROPDOWNBOX, TEXT_ALIGNMENT), Fade(GetColor(GuiGetStyle(DROPDOWNBOX, TEXT_COLOR_NORMAL)), guiAlpha)); + } + } + + // TODO: Avoid this function, use icon instead or 'v' + DrawTriangle(RAYGUI_CLITERAL(Vector2){ bounds.x + bounds.width - GuiGetStyle(DROPDOWNBOX, ARROW_PADDING), bounds.y + bounds.height/2 - 2 }, + RAYGUI_CLITERAL(Vector2){ bounds.x + bounds.width - GuiGetStyle(DROPDOWNBOX, ARROW_PADDING) + 5, bounds.y + bounds.height/2 - 2 + 5 }, + RAYGUI_CLITERAL(Vector2){ bounds.x + bounds.width - GuiGetStyle(DROPDOWNBOX, ARROW_PADDING) + 10, bounds.y + bounds.height/2 - 2 }, + Fade(GetColor(GuiGetStyle(DROPDOWNBOX, TEXT + (state*3))), guiAlpha)); + + //GuiDrawText("v", RAYGUI_CLITERAL(Rectangle){ bounds.x + bounds.width - GuiGetStyle(DROPDOWNBOX, ARROW_PADDING), bounds.y + bounds.height/2 - 2, 10, 10 }, + // GUI_TEXT_ALIGN_CENTER, Fade(GetColor(GuiGetStyle(DROPDOWNBOX, TEXT + (state*3))), guiAlpha)); + //-------------------------------------------------------------------- + + *active = itemSelected; + return pressed; +} + +// Text Box control, updates input text +// NOTE 1: Requires static variables: framesCounter +// NOTE 2: Returns if KEY_ENTER pressed (useful for data validation) +bool GuiTextBox(Rectangle bounds, char *text, int textSize, bool editMode) +{ + static int framesCounter = 0; // Required for blinking cursor + + GuiControlState state = guiState; + bool pressed = false; + + Rectangle cursor = { + bounds.x + GuiGetStyle(TEXTBOX, TEXT_PADDING) + GetTextWidth(text) + 2, + bounds.y + bounds.height/2 - GuiGetStyle(DEFAULT, TEXT_SIZE), + 1, + GuiGetStyle(DEFAULT, TEXT_SIZE)*2 + }; + + // Update control + //-------------------------------------------------------------------- + if ((state != GUI_STATE_DISABLED) && !guiLocked) + { + Vector2 mousePoint = GetMousePosition(); + + if (editMode) + { + state = GUI_STATE_PRESSED; + framesCounter++; + + int key = GetKeyPressed(); // Returns codepoint as Unicode + int keyCount = strlen(text); + + // Only allow keys in range [32..125] + if (keyCount < (textSize - 1)) + { + int maxWidth = (bounds.width - (GuiGetStyle(TEXTBOX, TEXT_INNER_PADDING)*2)); + + if ((GetTextWidth(text) < (maxWidth - GuiGetStyle(DEFAULT, TEXT_SIZE))) && (key >= 32)) + { + int byteLength = 0; + const char *textUtf8 = CodepointToUtf8(key, &byteLength); + + for (int i = 0; i < byteLength; i++) + { + text[keyCount] = textUtf8[i]; + keyCount++; + } + + text[keyCount] = '\0'; + } + } + + // Delete text + if (keyCount > 0) + { + if (IsKeyPressed(KEY_BACKSPACE)) + { + keyCount--; + text[keyCount] = '\0'; + framesCounter = 0; + if (keyCount < 0) keyCount = 0; + } + else if (IsKeyDown(KEY_BACKSPACE)) + { + if ((framesCounter > TEXTEDIT_CURSOR_BLINK_FRAMES) && (framesCounter%2) == 0) keyCount--; + text[keyCount] = '\0'; + if (keyCount < 0) keyCount = 0; + } + } + + if (IsKeyPressed(KEY_ENTER) || (!CheckCollisionPointRec(mousePoint, bounds) && IsMouseButtonPressed(MOUSE_LEFT_BUTTON))) pressed = true; + + // Check text alignment to position cursor properly + int textAlignment = GuiGetStyle(TEXTBOX, TEXT_ALIGNMENT); + if (textAlignment == GUI_TEXT_ALIGN_CENTER) cursor.x = bounds.x + GetTextWidth(text)/2 + bounds.width/2 + 1; + else if (textAlignment == GUI_TEXT_ALIGN_RIGHT) cursor.x = bounds.x + bounds.width - GuiGetStyle(TEXTBOX, TEXT_INNER_PADDING); + } + else + { + if (CheckCollisionPointRec(mousePoint, bounds)) + { + state = GUI_STATE_FOCUSED; + if (IsMouseButtonPressed(MOUSE_LEFT_BUTTON)) pressed = true; + } + } + + if (pressed) framesCounter = 0; + } + //-------------------------------------------------------------------- + + // Draw control + //-------------------------------------------------------------------- + if (state == GUI_STATE_PRESSED) + { + GuiDrawRectangle(bounds, GuiGetStyle(TEXTBOX, BORDER_WIDTH), Fade(GetColor(GuiGetStyle(TEXTBOX, BORDER + (state*3))), guiAlpha), Fade(GetColor(GuiGetStyle(TEXTBOX, BASE_COLOR_PRESSED)), guiAlpha)); + + // Draw blinking cursor + if (editMode && ((framesCounter/20)%2 == 0)) GuiDrawRectangle(cursor, 0, BLANK, Fade(GetColor(GuiGetStyle(TEXTBOX, BORDER_COLOR_PRESSED)), guiAlpha)); + } + else if (state == GUI_STATE_DISABLED) + { + GuiDrawRectangle(bounds, GuiGetStyle(TEXTBOX, BORDER_WIDTH), Fade(GetColor(GuiGetStyle(TEXTBOX, BORDER + (state*3))), guiAlpha), Fade(GetColor(GuiGetStyle(TEXTBOX, BASE_COLOR_DISABLED)), guiAlpha)); + } + else GuiDrawRectangle(bounds, 1, Fade(GetColor(GuiGetStyle(TEXTBOX, BORDER + (state*3))), guiAlpha), BLANK); + + GuiDrawText(text, GetTextBounds(TEXTBOX, bounds), GuiGetStyle(TEXTBOX, TEXT_ALIGNMENT), Fade(GetColor(GuiGetStyle(TEXTBOX, TEXT + (state*3))), guiAlpha)); + //-------------------------------------------------------------------- + + return pressed; +} + +// Spinner control, returns selected value +bool GuiSpinner(Rectangle bounds, const char *text, int *value, int minValue, int maxValue, bool editMode) +{ + GuiControlState state = guiState; + + bool pressed = false; + int tempValue = *value; + + Rectangle spinner = { bounds.x + GuiGetStyle(SPINNER, SPIN_BUTTON_WIDTH) + GuiGetStyle(SPINNER, SPIN_BUTTON_PADDING), bounds.y, + bounds.width - 2*(GuiGetStyle(SPINNER, SPIN_BUTTON_WIDTH) + GuiGetStyle(SPINNER, SPIN_BUTTON_PADDING)), bounds.height }; + Rectangle leftButtonBound = { (float)bounds.x, (float)bounds.y, (float)GuiGetStyle(SPINNER, SPIN_BUTTON_WIDTH), (float)bounds.height }; + Rectangle rightButtonBound = { (float)bounds.x + bounds.width - GuiGetStyle(SPINNER, SPIN_BUTTON_WIDTH), (float)bounds.y, (float)GuiGetStyle(SPINNER, SPIN_BUTTON_WIDTH), (float)bounds.height }; + + Rectangle textBounds = { 0 }; + if (text != NULL) + { + textBounds.width = GetTextWidth(text); + textBounds.height = GuiGetStyle(DEFAULT, TEXT_SIZE); + textBounds.x = bounds.x + bounds.width + GuiGetStyle(SPINNER, TEXT_PADDING); + textBounds.y = bounds.y + bounds.height/2 - GuiGetStyle(DEFAULT, TEXT_SIZE)/2; + if (GuiGetStyle(SPINNER, TEXT_ALIGNMENT) == GUI_TEXT_ALIGN_LEFT) textBounds.x = bounds.x - textBounds.width - GuiGetStyle(SPINNER, TEXT_PADDING); + } + + // Update control + //-------------------------------------------------------------------- + if ((state != GUI_STATE_DISABLED) && !guiLocked) + { + Vector2 mousePoint = GetMousePosition(); + + // Check spinner state + if (CheckCollisionPointRec(mousePoint, bounds)) + { + if (IsMouseButtonDown(MOUSE_LEFT_BUTTON)) state = GUI_STATE_PRESSED; + else state = GUI_STATE_FOCUSED; + } + } + + if (!editMode) + { + if (tempValue < minValue) tempValue = minValue; + if (tempValue > maxValue) tempValue = maxValue; + } + //-------------------------------------------------------------------- + + // Draw control + //-------------------------------------------------------------------- + // TODO: Set Spinner properties for ValueBox + pressed = GuiValueBox(spinner, NULL, &tempValue, minValue, maxValue, editMode); + + // Draw value selector custom buttons + // NOTE: BORDER_WIDTH and TEXT_ALIGNMENT forced values + int tempBorderWidth = GuiGetStyle(BUTTON, BORDER_WIDTH); + int tempTextAlign = GuiGetStyle(BUTTON, TEXT_ALIGNMENT); + GuiSetStyle(BUTTON, BORDER_WIDTH, GuiGetStyle(SPINNER, BORDER_WIDTH)); + GuiSetStyle(BUTTON, TEXT_ALIGNMENT, GUI_TEXT_ALIGN_CENTER); + +#if defined(RAYGUI_SUPPORT_ICONS) + if (GuiButton(leftButtonBound, GuiIconText(RICON_ARROW_LEFT_FILL, NULL))) tempValue--; + if (GuiButton(rightButtonBound, GuiIconText(RICON_ARROW_RIGHT_FILL, NULL))) tempValue++; +#else + if (GuiButton(leftButtonBound, "<")) tempValue--; + if (GuiButton(rightButtonBound, ">")) tempValue++; +#endif + + GuiSetStyle(BUTTON, TEXT_ALIGNMENT, tempTextAlign); + GuiSetStyle(BUTTON, BORDER_WIDTH, tempBorderWidth); + + // Draw text label if provided + if (text != NULL) GuiDrawText(text, textBounds, (GuiGetStyle(SPINNER, TEXT_ALIGNMENT) == GUI_TEXT_ALIGN_RIGHT)? GUI_TEXT_ALIGN_LEFT : GUI_TEXT_ALIGN_RIGHT, Fade(GetColor(GuiGetStyle(LABEL, TEXT + (state*3))), guiAlpha)); + //-------------------------------------------------------------------- + + *value = tempValue; + return pressed; +} + +// Value Box control, updates input text with numbers +// NOTE: Requires static variables: framesCounter +bool GuiValueBox(Rectangle bounds, const char *text, int *value, int minValue, int maxValue, bool editMode) +{ + #if !defined(VALUEBOX_MAX_CHARS) + #define VALUEBOX_MAX_CHARS 32 + #endif + + static int framesCounter = 0; // Required for blinking cursor + + GuiControlState state = guiState; + bool pressed = false; + + char textValue[VALUEBOX_MAX_CHARS + 1] = "\0"; + sprintf(textValue, "%i", *value); + + Rectangle textBounds = { 0 }; + if (text != NULL) + { + textBounds.width = GetTextWidth(text); + textBounds.height = GuiGetStyle(DEFAULT, TEXT_SIZE); + textBounds.x = bounds.x + bounds.width + GuiGetStyle(VALUEBOX, TEXT_PADDING); + textBounds.y = bounds.y + bounds.height/2 - GuiGetStyle(DEFAULT, TEXT_SIZE)/2; + if (GuiGetStyle(VALUEBOX, TEXT_ALIGNMENT) == GUI_TEXT_ALIGN_LEFT) textBounds.x = bounds.x - textBounds.width - GuiGetStyle(VALUEBOX, TEXT_PADDING); + } + + // Update control + //-------------------------------------------------------------------- + if ((state != GUI_STATE_DISABLED) && !guiLocked) + { + Vector2 mousePoint = GetMousePosition(); + + bool valueHasChanged = false; + + if (editMode) + { + state = GUI_STATE_PRESSED; + + framesCounter++; + + int keyCount = strlen(textValue); + + // Only allow keys in range [48..57] + if (keyCount < VALUEBOX_MAX_CHARS) + { + int maxWidth = bounds.width; + if (GetTextWidth(textValue) < maxWidth) + { + int key = GetKeyPressed(); + if ((key >= 48) && (key <= 57)) + { + textValue[keyCount] = (char)key; + keyCount++; + valueHasChanged = true; + } + } + } + + // Delete text + if (keyCount > 0) + { + if (IsKeyPressed(KEY_BACKSPACE)) + { + keyCount--; + textValue[keyCount] = '\0'; + framesCounter = 0; + if (keyCount < 0) keyCount = 0; + valueHasChanged = true; + } + else if (IsKeyDown(KEY_BACKSPACE)) + { + if ((framesCounter > TEXTEDIT_CURSOR_BLINK_FRAMES) && (framesCounter%2) == 0) keyCount--; + textValue[keyCount] = '\0'; + if (keyCount < 0) keyCount = 0; + valueHasChanged = true; + } + } + + if (valueHasChanged) *value = TextToInteger(textValue); + + if (IsKeyPressed(KEY_ENTER) || (!CheckCollisionPointRec(mousePoint, bounds) && IsMouseButtonPressed(MOUSE_LEFT_BUTTON))) pressed = true; + } + else + { + if (*value > maxValue) *value = maxValue; + else if (*value < minValue) *value = minValue; + + if (CheckCollisionPointRec(mousePoint, bounds)) + { + state = GUI_STATE_FOCUSED; + if (IsMouseButtonPressed(MOUSE_LEFT_BUTTON)) pressed = true; + } + } + + if (pressed) framesCounter = 0; + } + //-------------------------------------------------------------------- + + // Draw control + //-------------------------------------------------------------------- + Color baseColor = BLANK; + if (state == GUI_STATE_PRESSED) baseColor = GetColor(GuiGetStyle(VALUEBOX, BASE_COLOR_PRESSED)); + else if (state == GUI_STATE_DISABLED) baseColor = GetColor(GuiGetStyle(VALUEBOX, BASE_COLOR_DISABLED)); + + // WARNING: BLANK color does not work properly with Fade() + GuiDrawRectangle(bounds, GuiGetStyle(VALUEBOX, BORDER_WIDTH), Fade(GetColor(GuiGetStyle(VALUEBOX, BORDER + (state*3))), guiAlpha), baseColor); + GuiDrawText(textValue, GetTextBounds(VALUEBOX, bounds), GUI_TEXT_ALIGN_CENTER, Fade(GetColor(GuiGetStyle(VALUEBOX, TEXT + (state*3))), guiAlpha)); + + // Draw blinking cursor + if ((state == GUI_STATE_PRESSED) && (editMode && ((framesCounter/20)%2 == 0))) + { + // NOTE: ValueBox internal text is always centered + Rectangle cursor = { bounds.x + GetTextWidth(textValue)/2 + bounds.width/2 + 2, bounds.y + 2*GuiGetStyle(VALUEBOX, BORDER_WIDTH), 1, bounds.height - 4*GuiGetStyle(VALUEBOX, BORDER_WIDTH) }; + GuiDrawRectangle(cursor, 0, BLANK, Fade(GetColor(GuiGetStyle(VALUEBOX, BORDER_COLOR_PRESSED)), guiAlpha)); + } + + // Draw text label if provided + if (text != NULL) GuiDrawText(text, textBounds, (GuiGetStyle(VALUEBOX, TEXT_ALIGNMENT) == GUI_TEXT_ALIGN_RIGHT)? GUI_TEXT_ALIGN_LEFT : GUI_TEXT_ALIGN_RIGHT, Fade(GetColor(GuiGetStyle(LABEL, TEXT + (state*3))), guiAlpha)); + //-------------------------------------------------------------------- + + return pressed; +} + +// Text Box control with multiple lines +bool GuiTextBoxMulti(Rectangle bounds, char *text, int textSize, bool editMode) +{ + static int framesCounter = 0; // Required for blinking cursor + + GuiControlState state = guiState; + bool pressed = false; + + Rectangle textAreaBounds = { + bounds.x + GuiGetStyle(TEXTBOX, TEXT_INNER_PADDING), + bounds.y + GuiGetStyle(TEXTBOX, TEXT_INNER_PADDING), + bounds.width - 2*GuiGetStyle(TEXTBOX, TEXT_INNER_PADDING), + bounds.height - 2*GuiGetStyle(TEXTBOX, TEXT_INNER_PADDING) + }; + + // Cursor position, [x, y] values should be updated + Rectangle cursor = { 0, 0, 1, GuiGetStyle(DEFAULT, TEXT_SIZE) + 2 }; + + int textWidth = 0; + int currentLine = 0; + + // Update control + //-------------------------------------------------------------------- + if ((state != GUI_STATE_DISABLED) && !guiLocked) + { + Vector2 mousePoint = GetMousePosition(); + + if (editMode) + { + state = GUI_STATE_PRESSED; + framesCounter++; + + int key = GetKeyPressed(); + int keyCount = strlen(text); + + // Introduce characters + if (keyCount < (textSize - 1)) + { + Vector2 textSize = MeasureTextEx(guiFont, text, GuiGetStyle(DEFAULT, TEXT_SIZE), GuiGetStyle(DEFAULT, TEXT_SPACING)); + + if (textSize.y < (textAreaBounds.height - GuiGetStyle(DEFAULT, TEXT_SIZE))) + { + if (IsKeyPressed(KEY_ENTER)) + { + text[keyCount] = '\n'; + keyCount++; + } + else if (((key >= 32) && (key < 255))) // TODO: Support Unicode inputs + { + text[keyCount] = (char)key; + keyCount++; + } + } + } + + // Delete characters + if (keyCount > 0) + { + if (IsKeyPressed(KEY_BACKSPACE)) + { + keyCount--; + text[keyCount] = '\0'; + framesCounter = 0; + + if (keyCount < 0) keyCount = 0; + } + else if (IsKeyDown(KEY_BACKSPACE)) + { + if ((framesCounter > TEXTEDIT_CURSOR_BLINK_FRAMES) && (framesCounter%2) == 0) keyCount--; + text[keyCount] = '\0'; + + if (keyCount < 0) keyCount = 0; + } + } + + // Calculate cursor position considering text + char oneCharText[2] = { 0 }; + int lastBreakingPos = -1; + + for (int i = 0; i < keyCount && currentLine < keyCount; i++) + { + oneCharText[0] = text[i]; + textWidth += (GetTextWidth(oneCharText) + GuiGetStyle(DEFAULT, TEXT_SPACING)); + + if (text[i] == ' ' || text[i] == '\n') lastBreakingPos = i; + + if ( text[i] == '\n' || textWidth >= textAreaBounds.width) + { + currentLine++; + textWidth = 0; + + if (lastBreakingPos > 0) i = lastBreakingPos; + else textWidth += (GetTextWidth(oneCharText) + GuiGetStyle(DEFAULT, TEXT_SPACING)); + + lastBreakingPos = -1; + } + } + + cursor.x = bounds.x + GuiGetStyle(TEXTBOX, BORDER_WIDTH) + GuiGetStyle(TEXTBOX, TEXT_INNER_PADDING) + textWidth - GuiGetStyle(DEFAULT, TEXT_SPACING); + cursor.y = bounds.y + GuiGetStyle(TEXTBOX, BORDER_WIDTH) + GuiGetStyle(TEXTBOX, TEXT_INNER_PADDING)/2 + ((GuiGetStyle(DEFAULT, TEXT_SIZE) + GuiGetStyle(TEXTBOX, TEXT_INNER_PADDING))*currentLine); + + // Exit edit mode + if (!CheckCollisionPointRec(mousePoint, bounds) && IsMouseButtonPressed(MOUSE_LEFT_BUTTON)) pressed = true; + } + else + { + if (CheckCollisionPointRec(mousePoint, bounds)) + { + state = GUI_STATE_FOCUSED; + if (IsMouseButtonPressed(MOUSE_LEFT_BUTTON)) pressed = true; + } + } + + if (pressed) framesCounter = 0; // Reset blinking cursor + } + //-------------------------------------------------------------------- + + // Draw control + //-------------------------------------------------------------------- + if (state == GUI_STATE_PRESSED) + { + GuiDrawRectangle(bounds, GuiGetStyle(TEXTBOX, BORDER_WIDTH), Fade(GetColor(GuiGetStyle(TEXTBOX, BORDER + (state*3))), guiAlpha), Fade(GetColor(GuiGetStyle(TEXTBOX, BASE_COLOR_PRESSED)), guiAlpha)); + + // Draw blinking cursor + if (editMode && ((framesCounter/20)%2 == 0)) GuiDrawRectangle(cursor, 0, BLANK, Fade(GetColor(GuiGetStyle(TEXTBOX, BORDER_COLOR_PRESSED)), guiAlpha)); + } + else if (state == GUI_STATE_DISABLED) + { + GuiDrawRectangle(bounds, GuiGetStyle(TEXTBOX, BORDER_WIDTH), Fade(GetColor(GuiGetStyle(TEXTBOX, BORDER + (state*3))), guiAlpha), Fade(GetColor(GuiGetStyle(TEXTBOX, BASE_COLOR_DISABLED)), guiAlpha)); + } + else GuiDrawRectangle(bounds, 1, Fade(GetColor(GuiGetStyle(TEXTBOX, BORDER + (state*3))), guiAlpha), BLANK); + + DrawTextRec(guiFont, text, textAreaBounds, GuiGetStyle(DEFAULT, TEXT_SIZE), GuiGetStyle(DEFAULT, TEXT_SPACING), true, Fade(GetColor(GuiGetStyle(TEXTBOX, TEXT + (state*3))), guiAlpha)); + //-------------------------------------------------------------------- + + return pressed; +} + +// Slider control with pro parameters +// NOTE: Other GuiSlider*() controls use this one +float GuiSliderPro(Rectangle bounds, const char *textLeft, const char *textRight, float value, float minValue, float maxValue, int sliderWidth) +{ + GuiControlState state = guiState; + + int sliderValue = (int)(((value - minValue)/(maxValue - minValue))*(bounds.width - 2*GuiGetStyle(SLIDER, BORDER_WIDTH))); + + Rectangle slider = { bounds.x, bounds.y + GuiGetStyle(SLIDER, BORDER_WIDTH) + GuiGetStyle(SLIDER, SLIDER_PADDING), + 0, bounds.height - 2*GuiGetStyle(SLIDER, BORDER_WIDTH) - 2*GuiGetStyle(SLIDER, SLIDER_PADDING) }; + + if (sliderWidth > 0) // Slider + { + slider.x += (sliderValue - sliderWidth/2); + slider.width = sliderWidth; + } + else if (sliderWidth == 0) // SliderBar + { + slider.x += GuiGetStyle(SLIDER, BORDER_WIDTH); + slider.width = sliderValue; + } + + // Update control + //-------------------------------------------------------------------- + if ((state != GUI_STATE_DISABLED) && !guiLocked) + { + Vector2 mousePoint = GetMousePosition(); + + if (CheckCollisionPointRec(mousePoint, bounds)) + { + if (IsMouseButtonDown(MOUSE_LEFT_BUTTON)) + { + state = GUI_STATE_PRESSED; + + // Get equivalent value and slider position from mousePoint.x + value = ((maxValue - minValue)*(mousePoint.x - (float)(bounds.x + sliderWidth/2)))/(float)(bounds.width - sliderWidth) + minValue; + + if (sliderWidth > 0) slider.x = mousePoint.x - slider.width/2; // Slider + else if (sliderWidth == 0) slider.width = sliderValue; // SliderBar + } + else state = GUI_STATE_FOCUSED; + } + + if (value > maxValue) value = maxValue; + else if (value < minValue) value = minValue; + } + + // Bar limits check + if (sliderWidth > 0) // Slider + { + if (slider.x <= (bounds.x + GuiGetStyle(SLIDER, BORDER_WIDTH))) slider.x = bounds.x + GuiGetStyle(SLIDER, BORDER_WIDTH); + else if ((slider.x + slider.width) >= (bounds.x + bounds.width)) slider.x = bounds.x + bounds.width - slider.width - GuiGetStyle(SLIDER, BORDER_WIDTH); + } + else if (sliderWidth == 0) // SliderBar + { + if (slider.width > bounds.width) slider.width = bounds.width - 2*GuiGetStyle(SLIDER, BORDER_WIDTH); + } + //-------------------------------------------------------------------- + + // Draw control + //-------------------------------------------------------------------- + GuiDrawRectangle(bounds, GuiGetStyle(SLIDER, BORDER_WIDTH), Fade(GetColor(GuiGetStyle(SLIDER, BORDER + (state*3))), guiAlpha), Fade(GetColor(GuiGetStyle(SLIDER, (state != GUI_STATE_DISABLED)? BASE_COLOR_NORMAL : BASE_COLOR_DISABLED)), guiAlpha)); + + // Draw slider internal bar (depends on state) + if ((state == GUI_STATE_NORMAL) || (state == GUI_STATE_PRESSED)) GuiDrawRectangle(slider, 0, BLANK, Fade(GetColor(GuiGetStyle(SLIDER, BASE_COLOR_PRESSED)), guiAlpha)); + else if (state == GUI_STATE_FOCUSED) GuiDrawRectangle(slider, 0, BLANK, Fade(GetColor(GuiGetStyle(SLIDER, TEXT_COLOR_FOCUSED)), guiAlpha)); + + // Draw left/right text if provided + if (textLeft != NULL) + { + Rectangle textBounds = { 0 }; + textBounds.width = GetTextWidth(textLeft); // TODO: Consider text icon + textBounds.height = GuiGetStyle(DEFAULT, TEXT_SIZE); + textBounds.x = bounds.x - textBounds.width - GuiGetStyle(SLIDER, TEXT_PADDING); + textBounds.y = bounds.y + bounds.height/2 - GuiGetStyle(DEFAULT, TEXT_SIZE)/2; + + GuiDrawText(textLeft, textBounds, GUI_TEXT_ALIGN_RIGHT, Fade(GetColor(GuiGetStyle(SLIDER, TEXT + (state*3))), guiAlpha)); + } + + if (textRight != NULL) + { + Rectangle textBounds = { 0 }; + textBounds.width = GetTextWidth(textRight); // TODO: Consider text icon + textBounds.height = GuiGetStyle(DEFAULT, TEXT_SIZE); + textBounds.x = bounds.x + bounds.width + GuiGetStyle(SLIDER, TEXT_PADDING); + textBounds.y = bounds.y + bounds.height/2 - GuiGetStyle(DEFAULT, TEXT_SIZE)/2; + + GuiDrawText(textRight, textBounds, GUI_TEXT_ALIGN_LEFT, Fade(GetColor(GuiGetStyle(SLIDER, TEXT + (state*3))), guiAlpha)); + } + //-------------------------------------------------------------------- + + return value; +} + +// Slider control extended, returns selected value and has text +float GuiSlider(Rectangle bounds, const char *textLeft, const char *textRight, float value, float minValue, float maxValue) +{ + return GuiSliderPro(bounds, textLeft, textRight, value, minValue, maxValue, GuiGetStyle(SLIDER, SLIDER_WIDTH)); +} + +// Slider Bar control extended, returns selected value +float GuiSliderBar(Rectangle bounds, const char *textLeft, const char *textRight, float value, float minValue, float maxValue) +{ + return GuiSliderPro(bounds, textLeft, textRight, value, minValue, maxValue, 0); +} + +// Progress Bar control extended, shows current progress value +float GuiProgressBar(Rectangle bounds, const char *textLeft, const char *textRight, float value, float minValue, float maxValue) +{ + GuiControlState state = guiState; + + Rectangle progress = { bounds.x + GuiGetStyle(PROGRESSBAR, BORDER_WIDTH), + bounds.y + GuiGetStyle(PROGRESSBAR, BORDER_WIDTH) + GuiGetStyle(PROGRESSBAR, PROGRESS_PADDING), 0, + bounds.height - 2*GuiGetStyle(PROGRESSBAR, BORDER_WIDTH) - 2*GuiGetStyle(PROGRESSBAR, PROGRESS_PADDING) }; + + // Update control + //-------------------------------------------------------------------- + if (state != GUI_STATE_DISABLED) progress.width = (int)(value/(maxValue - minValue)*(float)(bounds.width - 2*GuiGetStyle(PROGRESSBAR, BORDER_WIDTH))); + //-------------------------------------------------------------------- + + // Draw control + //-------------------------------------------------------------------- + GuiDrawRectangle(bounds, GuiGetStyle(PROGRESSBAR, BORDER_WIDTH), Fade(GetColor(GuiGetStyle(PROGRESSBAR, BORDER + (state*3))), guiAlpha), BLANK); + + // Draw slider internal progress bar (depends on state) + if ((state == GUI_STATE_NORMAL) || (state == GUI_STATE_PRESSED)) GuiDrawRectangle(progress, 0, BLANK, Fade(GetColor(GuiGetStyle(PROGRESSBAR, BASE_COLOR_PRESSED)), guiAlpha)); + else if (state == GUI_STATE_FOCUSED) GuiDrawRectangle(progress, 0, BLANK, Fade(GetColor(GuiGetStyle(PROGRESSBAR, TEXT_COLOR_FOCUSED)), guiAlpha)); + + // Draw left/right text if provided + if (textLeft != NULL) + { + Rectangle textBounds = { 0 }; + textBounds.width = GetTextWidth(textLeft); // TODO: Consider text icon + textBounds.height = GuiGetStyle(DEFAULT, TEXT_SIZE); + textBounds.x = bounds.x - textBounds.width - GuiGetStyle(PROGRESSBAR, TEXT_PADDING); + textBounds.y = bounds.y + bounds.height/2 - GuiGetStyle(DEFAULT, TEXT_SIZE)/2; + + GuiDrawText(textLeft, textBounds, GUI_TEXT_ALIGN_RIGHT, Fade(GetColor(GuiGetStyle(PROGRESSBAR, TEXT + (state*3))), guiAlpha)); + } + + if (textRight != NULL) + { + Rectangle textBounds = { 0 }; + textBounds.width = GetTextWidth(textRight); // TODO: Consider text icon + textBounds.height = GuiGetStyle(DEFAULT, TEXT_SIZE); + textBounds.x = bounds.x + bounds.width + GuiGetStyle(PROGRESSBAR, TEXT_PADDING); + textBounds.y = bounds.y + bounds.height/2 - GuiGetStyle(DEFAULT, TEXT_SIZE)/2; + + GuiDrawText(textRight, textBounds, GUI_TEXT_ALIGN_LEFT, Fade(GetColor(GuiGetStyle(PROGRESSBAR, TEXT + (state*3))), guiAlpha)); + } + //-------------------------------------------------------------------- + + return value; +} + +// Status Bar control +void GuiStatusBar(Rectangle bounds, const char *text) +{ + GuiControlState state = guiState; + + // Draw control + //-------------------------------------------------------------------- + GuiDrawRectangle(bounds, GuiGetStyle(STATUSBAR, BORDER_WIDTH), Fade(GetColor(GuiGetStyle(STATUSBAR, (state != GUI_STATE_DISABLED)? BORDER_COLOR_NORMAL : BORDER_COLOR_DISABLED)), guiAlpha), + Fade(GetColor(GuiGetStyle(STATUSBAR, (state != GUI_STATE_DISABLED)? BASE_COLOR_NORMAL : BASE_COLOR_DISABLED)), guiAlpha)); + GuiDrawText(text, GetTextBounds(STATUSBAR, bounds), GuiGetStyle(STATUSBAR, TEXT_ALIGNMENT), Fade(GetColor(GuiGetStyle(STATUSBAR, (state != GUI_STATE_DISABLED)? TEXT_COLOR_NORMAL : TEXT_COLOR_DISABLED)), guiAlpha)); + //-------------------------------------------------------------------- +} + +// Dummy rectangle control, intended for placeholding +void GuiDummyRec(Rectangle bounds, const char *text) +{ + GuiControlState state = guiState; + + // Update control + //-------------------------------------------------------------------- + if ((state != GUI_STATE_DISABLED) && !guiLocked) + { + Vector2 mousePoint = GetMousePosition(); + + // Check button state + if (CheckCollisionPointRec(mousePoint, bounds)) + { + if (IsMouseButtonDown(MOUSE_LEFT_BUTTON)) state = GUI_STATE_PRESSED; + else state = GUI_STATE_FOCUSED; + } + } + //-------------------------------------------------------------------- + + // Draw control + //-------------------------------------------------------------------- + GuiDrawRectangle(bounds, 0, BLANK, Fade(GetColor(GuiGetStyle(DEFAULT, (state != GUI_STATE_DISABLED)? BASE_COLOR_NORMAL : BASE_COLOR_DISABLED)), guiAlpha)); + GuiDrawText(text, GetTextBounds(DEFAULT, bounds), GUI_TEXT_ALIGN_CENTER, Fade(GetColor(GuiGetStyle(BUTTON, (state != GUI_STATE_DISABLED)? TEXT_COLOR_NORMAL : TEXT_COLOR_DISABLED)), guiAlpha)); + //------------------------------------------------------------------ +} + +// Scroll Bar control +// TODO: I feel GuiScrollBar could be simplified... +int GuiScrollBar(Rectangle bounds, int value, int minValue, int maxValue) +{ + GuiControlState state = guiState; + + // Is the scrollbar horizontal or vertical? + bool isVertical = (bounds.width > bounds.height)? false : true; + + // The size (width or height depending on scrollbar type) of the spinner buttons + const int spinnerSize = GuiGetStyle(SCROLLBAR, ARROWS_VISIBLE)? (isVertical? bounds.width - 2*GuiGetStyle(SCROLLBAR, BORDER_WIDTH) : bounds.height - 2*GuiGetStyle(SCROLLBAR, BORDER_WIDTH)) : 0; + + // Arrow buttons [<] [>] [∧] [∨] + Rectangle arrowUpLeft = { 0 }; + Rectangle arrowDownRight = { 0 }; + + // Actual area of the scrollbar excluding the arrow buttons + Rectangle scrollbar = { 0 }; + + // Slider bar that moves --[///]----- + Rectangle slider = { 0 }; + + // Normalize value + if (value > maxValue) value = maxValue; + if (value < minValue) value = minValue; + + const int range = maxValue - minValue; + int sliderSize = GuiGetStyle(SCROLLBAR, SCROLL_SLIDER_SIZE); + + // Calculate rectangles for all of the components + arrowUpLeft = RAYGUI_CLITERAL(Rectangle){ (float)bounds.x + GuiGetStyle(SCROLLBAR, BORDER_WIDTH), (float)bounds.y + GuiGetStyle(SCROLLBAR, BORDER_WIDTH), (float)spinnerSize, (float)spinnerSize }; + + if (isVertical) + { + arrowDownRight = RAYGUI_CLITERAL(Rectangle){ (float)bounds.x + GuiGetStyle(SCROLLBAR, BORDER_WIDTH), (float)bounds.y + bounds.height - spinnerSize - GuiGetStyle(SCROLLBAR, BORDER_WIDTH), (float)spinnerSize, (float)spinnerSize}; + scrollbar = RAYGUI_CLITERAL(Rectangle){ bounds.x + GuiGetStyle(SCROLLBAR, BORDER_WIDTH) + GuiGetStyle(SCROLLBAR, SCROLL_PADDING), arrowUpLeft.y + arrowUpLeft.height, bounds.width - 2*(GuiGetStyle(SCROLLBAR, BORDER_WIDTH) + GuiGetStyle(SCROLLBAR, SCROLL_PADDING)), bounds.height - arrowUpLeft.height - arrowDownRight.height - 2*GuiGetStyle(SCROLLBAR, BORDER_WIDTH) }; + sliderSize = (sliderSize >= scrollbar.height)? (scrollbar.height - 2) : sliderSize; // Make sure the slider won't get outside of the scrollbar + slider = RAYGUI_CLITERAL(Rectangle){ (float)bounds.x + GuiGetStyle(SCROLLBAR, BORDER_WIDTH) + GuiGetStyle(SCROLLBAR, SCROLL_SLIDER_PADDING), (float)scrollbar.y + (int)(((float)(value - minValue)/range)*(scrollbar.height - sliderSize)), (float)bounds.width - 2*(GuiGetStyle(SCROLLBAR, BORDER_WIDTH) + GuiGetStyle(SCROLLBAR, SCROLL_SLIDER_PADDING)), (float)sliderSize }; + } + else + { + arrowDownRight = RAYGUI_CLITERAL(Rectangle){ (float)bounds.x + bounds.width - spinnerSize - GuiGetStyle(SCROLLBAR, BORDER_WIDTH), (float)bounds.y + GuiGetStyle(SCROLLBAR, BORDER_WIDTH), (float)spinnerSize, (float)spinnerSize}; + scrollbar = RAYGUI_CLITERAL(Rectangle){ arrowUpLeft.x + arrowUpLeft.width, bounds.y + GuiGetStyle(SCROLLBAR, BORDER_WIDTH) + GuiGetStyle(SCROLLBAR, SCROLL_PADDING), bounds.width - arrowUpLeft.width - arrowDownRight.width - 2*GuiGetStyle(SCROLLBAR, BORDER_WIDTH), bounds.height - 2*(GuiGetStyle(SCROLLBAR, BORDER_WIDTH) + GuiGetStyle(SCROLLBAR, SCROLL_PADDING))}; + sliderSize = (sliderSize >= scrollbar.width)? (scrollbar.width - 2) : sliderSize; // Make sure the slider won't get outside of the scrollbar + slider = RAYGUI_CLITERAL(Rectangle){ (float)scrollbar.x + (int)(((float)(value - minValue)/range)*(scrollbar.width - sliderSize)), (float)bounds.y + GuiGetStyle(SCROLLBAR, BORDER_WIDTH) + GuiGetStyle(SCROLLBAR, SCROLL_SLIDER_PADDING), (float)sliderSize, (float)bounds.height - 2*(GuiGetStyle(SCROLLBAR, BORDER_WIDTH) + GuiGetStyle(SCROLLBAR, SCROLL_SLIDER_PADDING)) }; + } + + // Update control + //-------------------------------------------------------------------- + if ((state != GUI_STATE_DISABLED) && !guiLocked) + { + Vector2 mousePoint = GetMousePosition(); + + if (CheckCollisionPointRec(mousePoint, bounds)) + { + state = GUI_STATE_FOCUSED; + + // Handle mouse wheel + int wheel = GetMouseWheelMove(); + if (wheel != 0) value += wheel; + + if (IsMouseButtonPressed(MOUSE_LEFT_BUTTON)) + { + if (CheckCollisionPointRec(mousePoint, arrowUpLeft)) value -= range/GuiGetStyle(SCROLLBAR, SCROLL_SPEED); + else if (CheckCollisionPointRec(mousePoint, arrowDownRight)) value += range/GuiGetStyle(SCROLLBAR, SCROLL_SPEED); + + state = GUI_STATE_PRESSED; + } + else if (IsMouseButtonDown(MOUSE_LEFT_BUTTON)) + { + if (!isVertical) + { + Rectangle scrollArea = { arrowUpLeft.x + arrowUpLeft.width, arrowUpLeft.y, scrollbar.width, bounds.height - 2*GuiGetStyle(SCROLLBAR, BORDER_WIDTH)}; + if (CheckCollisionPointRec(mousePoint, scrollArea)) value = ((float)(mousePoint.x - scrollArea.x - slider.width/2)*range)/(scrollArea.width - slider.width) + minValue; + } + else + { + Rectangle scrollArea = { arrowUpLeft.x, arrowUpLeft.y+arrowUpLeft.height, bounds.width - 2*GuiGetStyle(SCROLLBAR, BORDER_WIDTH), scrollbar.height}; + if (CheckCollisionPointRec(mousePoint, scrollArea)) value = ((float)(mousePoint.y - scrollArea.y - slider.height/2)*range)/(scrollArea.height - slider.height) + minValue; + } + } + } + + // Normalize value + if (value > maxValue) value = maxValue; + if (value < minValue) value = minValue; + } + //-------------------------------------------------------------------- + + // Draw control + //-------------------------------------------------------------------- + GuiDrawRectangle(bounds, GuiGetStyle(SCROLLBAR, BORDER_WIDTH), Fade(GetColor(GuiGetStyle(LISTVIEW, BORDER + state*3)), guiAlpha), Fade(GetColor(GuiGetStyle(DEFAULT, BORDER_COLOR_DISABLED)), guiAlpha)); // Draw the background + + GuiDrawRectangle(scrollbar, 0, BLANK, Fade(GetColor(GuiGetStyle(BUTTON, BASE_COLOR_NORMAL)), guiAlpha)); // Draw the scrollbar active area background + GuiDrawRectangle(slider, 0, BLANK, Fade(GetColor(GuiGetStyle(SLIDER, BORDER + state*3)), guiAlpha)); // Draw the slider bar + + // Draw arrows + const int padding = (spinnerSize - GuiGetStyle(SCROLLBAR, ARROWS_SIZE))/2; + const Vector2 lineCoords[] = + { + // Coordinates for < 0,1,2 + { arrowUpLeft.x + padding, arrowUpLeft.y + spinnerSize/2 }, + { arrowUpLeft.x + spinnerSize - padding, arrowUpLeft.y + padding }, + { arrowUpLeft.x + spinnerSize - padding, arrowUpLeft.y + spinnerSize - padding }, + + // Coordinates for > 3,4,5 + { arrowDownRight.x + padding, arrowDownRight.y + padding }, + { arrowDownRight.x + spinnerSize - padding, arrowDownRight.y + spinnerSize/2 }, + { arrowDownRight.x + padding, arrowDownRight.y + spinnerSize - padding }, + + // Coordinates for ∧ 6,7,8 + { arrowUpLeft.x + spinnerSize/2, arrowUpLeft.y + padding }, + { arrowUpLeft.x + padding, arrowUpLeft.y + spinnerSize - padding }, + { arrowUpLeft.x + spinnerSize - padding, arrowUpLeft.y + spinnerSize - padding }, + + // Coordinates for ∨ 9,10,11 + { arrowDownRight.x + padding, arrowDownRight.y + padding }, + { arrowDownRight.x + spinnerSize/2, arrowDownRight.y + spinnerSize - padding }, + { arrowDownRight.x + spinnerSize - padding, arrowDownRight.y + padding } + }; + + Color lineColor = Fade(GetColor(GuiGetStyle(BUTTON, TEXT + state*3)), guiAlpha); + + if (GuiGetStyle(SCROLLBAR, ARROWS_VISIBLE)) + { + if (isVertical) + { + DrawTriangle(lineCoords[6], lineCoords[7], lineCoords[8], lineColor); + DrawTriangle(lineCoords[9], lineCoords[10], lineCoords[11], lineColor); + } + else + { + DrawTriangle(lineCoords[2], lineCoords[1], lineCoords[0], lineColor); + DrawTriangle(lineCoords[5], lineCoords[4], lineCoords[3], lineColor); + } + } + //-------------------------------------------------------------------- + + return value; +} + +// List View control +int GuiListView(Rectangle bounds, const char *text, int *scrollIndex, int active) +{ + int itemsCount = 0; + const char **items = NULL; + + if (text != NULL) items = GuiTextSplit(text, &itemsCount, NULL); + + return GuiListViewEx(bounds, items, itemsCount, NULL, scrollIndex, active); +} + +// List View control with extended parameters +int GuiListViewEx(Rectangle bounds, const char **text, int count, int *focus, int *scrollIndex, int active) +{ + GuiControlState state = guiState; + int itemFocused = (focus == NULL)? -1 : *focus; + int itemSelected = active; + + // Check if we need a scroll bar + bool useScrollBar = false; + if ((GuiGetStyle(LISTVIEW, LIST_ITEMS_HEIGHT) + GuiGetStyle(LISTVIEW, LIST_ITEMS_PADDING))*count > bounds.height) useScrollBar = true; + + // Define base item rectangle [0] + Rectangle itemBounds = { 0 }; + itemBounds.x = bounds.x + GuiGetStyle(LISTVIEW, LIST_ITEMS_PADDING); + itemBounds.y = bounds.y + GuiGetStyle(LISTVIEW, LIST_ITEMS_PADDING) + GuiGetStyle(DEFAULT, BORDER_WIDTH); + itemBounds.width = bounds.width - 2*GuiGetStyle(LISTVIEW, LIST_ITEMS_PADDING) - GuiGetStyle(DEFAULT, BORDER_WIDTH); + itemBounds.height = GuiGetStyle(LISTVIEW, LIST_ITEMS_HEIGHT); + if (useScrollBar) itemBounds.width -= GuiGetStyle(LISTVIEW, SCROLLBAR_WIDTH); + + // Get items on the list + int visibleItems = bounds.height/(GuiGetStyle(LISTVIEW, LIST_ITEMS_HEIGHT) + GuiGetStyle(LISTVIEW, LIST_ITEMS_PADDING)); + if (visibleItems > count) visibleItems = count; + + int startIndex = (scrollIndex == NULL)? 0 : *scrollIndex; + if ((startIndex < 0) || (startIndex > (count - visibleItems))) startIndex = 0; + int endIndex = startIndex + visibleItems; + + // Update control + //-------------------------------------------------------------------- + if ((state != GUI_STATE_DISABLED) && !guiLocked) + { + Vector2 mousePoint = GetMousePosition(); + + // Check mouse inside list view + if (CheckCollisionPointRec(mousePoint, bounds)) + { + state = GUI_STATE_FOCUSED; + + // Check focused and selected item + for (int i = 0; i < visibleItems; i++) + { + if (CheckCollisionPointRec(mousePoint, itemBounds)) + { + itemFocused = startIndex + i; + if (IsMouseButtonPressed(MOUSE_LEFT_BUTTON)) + { + if (itemSelected == (startIndex + i)) itemSelected = -1; + else itemSelected = startIndex + i; + } + break; + } + + // Update item rectangle y position for next item + itemBounds.y += (GuiGetStyle(LISTVIEW, LIST_ITEMS_HEIGHT) + GuiGetStyle(LISTVIEW, LIST_ITEMS_PADDING)); + } + + if (useScrollBar) + { + int wheelMove = GetMouseWheelMove(); + startIndex -= wheelMove; + + if (startIndex < 0) startIndex = 0; + else if (startIndex > (count - visibleItems)) startIndex = count - visibleItems; + + endIndex = startIndex + visibleItems; + if (endIndex > count) endIndex = count; + } + } + else itemFocused = -1; + + // Reset item rectangle y to [0] + itemBounds.y = bounds.y + GuiGetStyle(LISTVIEW, LIST_ITEMS_PADDING) + GuiGetStyle(DEFAULT, BORDER_WIDTH); + } + //-------------------------------------------------------------------- + + // Draw control + //-------------------------------------------------------------------- + GuiDrawRectangle(bounds, GuiGetStyle(DEFAULT, BORDER_WIDTH), Fade(GetColor(GuiGetStyle(LISTVIEW, BORDER + state*3)), guiAlpha), GetColor(GuiGetStyle(DEFAULT, BACKGROUND_COLOR))); // Draw background + + // Draw visible items + for (int i = 0; ((i < visibleItems) && (text != NULL)); i++) + { + if (state == GUI_STATE_DISABLED) + { + if ((startIndex + i) == itemSelected) GuiDrawRectangle(itemBounds, GuiGetStyle(LISTVIEW, BORDER_WIDTH), Fade(GetColor(GuiGetStyle(LISTVIEW, BORDER_COLOR_DISABLED)), guiAlpha), Fade(GetColor(GuiGetStyle(LISTVIEW, BASE_COLOR_DISABLED)), guiAlpha)); + + GuiDrawText(text[startIndex + i], GetTextBounds(DEFAULT, itemBounds), GuiGetStyle(LISTVIEW, TEXT_ALIGNMENT), Fade(GetColor(GuiGetStyle(LISTVIEW, TEXT_COLOR_DISABLED)), guiAlpha)); + } + else + { + if ((startIndex + i) == itemSelected) + { + // Draw item selected + GuiDrawRectangle(itemBounds, GuiGetStyle(LISTVIEW, BORDER_WIDTH), Fade(GetColor(GuiGetStyle(LISTVIEW, BORDER_COLOR_PRESSED)), guiAlpha), Fade(GetColor(GuiGetStyle(LISTVIEW, BASE_COLOR_PRESSED)), guiAlpha)); + GuiDrawText(text[startIndex + i], GetTextBounds(DEFAULT, itemBounds), GuiGetStyle(LISTVIEW, TEXT_ALIGNMENT), Fade(GetColor(GuiGetStyle(LISTVIEW, TEXT_COLOR_PRESSED)), guiAlpha)); + } + else if ((startIndex + i) == itemFocused) + { + // Draw item focused + GuiDrawRectangle(itemBounds, GuiGetStyle(LISTVIEW, BORDER_WIDTH), Fade(GetColor(GuiGetStyle(LISTVIEW, BORDER_COLOR_FOCUSED)), guiAlpha), Fade(GetColor(GuiGetStyle(LISTVIEW, BASE_COLOR_FOCUSED)), guiAlpha)); + GuiDrawText(text[startIndex + i], GetTextBounds(DEFAULT, itemBounds), GuiGetStyle(LISTVIEW, TEXT_ALIGNMENT), Fade(GetColor(GuiGetStyle(LISTVIEW, TEXT_COLOR_FOCUSED)), guiAlpha)); + } + else + { + // Draw item normal + GuiDrawText(text[startIndex + i], GetTextBounds(DEFAULT, itemBounds), GuiGetStyle(LISTVIEW, TEXT_ALIGNMENT), Fade(GetColor(GuiGetStyle(LISTVIEW, TEXT_COLOR_NORMAL)), guiAlpha)); + } + } + + // Update item rectangle y position for next item + itemBounds.y += (GuiGetStyle(LISTVIEW, LIST_ITEMS_HEIGHT) + GuiGetStyle(LISTVIEW, LIST_ITEMS_PADDING)); + } + + if (useScrollBar) + { + Rectangle scrollBarBounds = { + bounds.x + bounds.width - GuiGetStyle(LISTVIEW, BORDER_WIDTH) - GuiGetStyle(LISTVIEW, SCROLLBAR_WIDTH), + bounds.y + GuiGetStyle(LISTVIEW, BORDER_WIDTH), (float)GuiGetStyle(LISTVIEW, SCROLLBAR_WIDTH), + bounds.height - 2*GuiGetStyle(DEFAULT, BORDER_WIDTH) + }; + + // Calculate percentage of visible items and apply same percentage to scrollbar + float percentVisible = (float)(endIndex - startIndex)/count; + float sliderSize = bounds.height*percentVisible; + + int prevSliderSize = GuiGetStyle(SCROLLBAR, SCROLL_SLIDER_SIZE); // Save default slider size + int prevScrollSpeed = GuiGetStyle(SCROLLBAR, SCROLL_SPEED); // Save default scroll speed + GuiSetStyle(SCROLLBAR, SCROLL_SLIDER_SIZE, sliderSize); // Change slider size + GuiSetStyle(SCROLLBAR, SCROLL_SPEED, count - visibleItems); // Change scroll speed + + startIndex = GuiScrollBar(scrollBarBounds, startIndex, 0, count - visibleItems); + + GuiSetStyle(SCROLLBAR, SCROLL_SPEED, prevScrollSpeed); // Reset scroll speed to default + GuiSetStyle(SCROLLBAR, SCROLL_SLIDER_SIZE, prevSliderSize); // Reset slider size to default + } + //-------------------------------------------------------------------- + + if (focus != NULL) *focus = itemFocused; + if (scrollIndex != NULL) *scrollIndex = startIndex; + + return itemSelected; +} + +// Color Panel control +Color GuiColorPanelEx(Rectangle bounds, Color color, float hue) +{ + GuiControlState state = guiState; + Vector2 pickerSelector = { 0 }; + + Vector3 vcolor = { (float)color.r/255.0f, (float)color.g/255.0f, (float)color.b/255.0f }; + Vector3 hsv = ConvertRGBtoHSV(vcolor); + + pickerSelector.x = bounds.x + (float)hsv.y*bounds.width; // HSV: Saturation + pickerSelector.y = bounds.y + (1.0f - (float)hsv.z)*bounds.height; // HSV: Value + + Vector3 maxHue = { hue >= 0.0f ? hue : hsv.x, 1.0f, 1.0f }; + Vector3 rgbHue = ConvertHSVtoRGB(maxHue); + Color maxHueCol = { (unsigned char)(255.0f*rgbHue.x), + (unsigned char)(255.0f*rgbHue.y), + (unsigned char)(255.0f*rgbHue.z), 255 }; + + const Color colWhite = { 255, 255, 255, 255 }; + const Color colBlack = { 0, 0, 0, 255 }; + + // Update control + //-------------------------------------------------------------------- + if ((state != GUI_STATE_DISABLED) && !guiLocked) + { + Vector2 mousePoint = GetMousePosition(); + + if (CheckCollisionPointRec(mousePoint, bounds)) + { + if (IsMouseButtonDown(MOUSE_LEFT_BUTTON)) + { + state = GUI_STATE_PRESSED; + pickerSelector = mousePoint; + + // Calculate color from picker + Vector2 colorPick = { pickerSelector.x - bounds.x, pickerSelector.y - bounds.y }; + + colorPick.x /= (float)bounds.width; // Get normalized value on x + colorPick.y /= (float)bounds.height; // Get normalized value on y + + hsv.y = colorPick.x; + hsv.z = 1.0f - colorPick.y; + + Vector3 rgb = ConvertHSVtoRGB(hsv); + + // NOTE: Vector3ToColor() only available on raylib 1.8.1 + color = RAYGUI_CLITERAL(Color){ (unsigned char)(255.0f*rgb.x), + (unsigned char)(255.0f*rgb.y), + (unsigned char)(255.0f*rgb.z), + (unsigned char)(255.0f*(float)color.a/255.0f) }; + + } + else state = GUI_STATE_FOCUSED; + } + } + //-------------------------------------------------------------------- + + // Draw control + //-------------------------------------------------------------------- + if (state != GUI_STATE_DISABLED) + { + DrawRectangleGradientEx(bounds, Fade(colWhite, guiAlpha), Fade(colWhite, guiAlpha), Fade(maxHueCol, guiAlpha), Fade(maxHueCol, guiAlpha)); + DrawRectangleGradientEx(bounds, Fade(colBlack, 0), Fade(colBlack, guiAlpha), Fade(colBlack, guiAlpha), Fade(colBlack, 0)); + + // Draw color picker: selector + Rectangle selector = { pickerSelector.x - GuiGetStyle(COLORPICKER, COLOR_SELECTOR_SIZE)/2, pickerSelector.y - GuiGetStyle(COLORPICKER, COLOR_SELECTOR_SIZE)/2, GuiGetStyle(COLORPICKER, COLOR_SELECTOR_SIZE), GuiGetStyle(COLORPICKER, COLOR_SELECTOR_SIZE) }; + GuiDrawRectangle(selector, 0, BLANK, Fade(colWhite, guiAlpha)); + } + else + { + DrawRectangleGradientEx(bounds, Fade(Fade(GetColor(GuiGetStyle(COLORPICKER, BASE_COLOR_DISABLED)), 0.1f), guiAlpha), Fade(Fade(colBlack, 0.6f), guiAlpha), Fade(Fade(colBlack, 0.6f), guiAlpha), Fade(Fade(GetColor(GuiGetStyle(COLORPICKER, BORDER_COLOR_DISABLED)), 0.6f), guiAlpha)); + } + + GuiDrawRectangle(bounds, 1, Fade(GetColor(GuiGetStyle(COLORPICKER, BORDER + state*3)), guiAlpha), BLANK); + //-------------------------------------------------------------------- + + return color; +} + +Color GuiColorPanel(Rectangle bounds, Color color) +{ + return GuiColorPanelEx(bounds, color, -1.0f); +} + +// Color Bar Alpha control +// NOTE: Returns alpha value normalized [0..1] +float GuiColorBarAlpha(Rectangle bounds, float alpha) +{ + #define COLORBARALPHA_CHECKED_SIZE 10 + + GuiControlState state = guiState; + Rectangle selector = { (float)bounds.x + alpha*bounds.width - GuiGetStyle(COLORPICKER, HUEBAR_SELECTOR_OVERFLOW), (float)bounds.y - GuiGetStyle(COLORPICKER, HUEBAR_SELECTOR_OVERFLOW), (float)GuiGetStyle(COLORPICKER, HUEBAR_SELECTOR_HEIGHT), (float)bounds.height + GuiGetStyle(COLORPICKER, HUEBAR_SELECTOR_OVERFLOW)*2 }; + + // Update control + //-------------------------------------------------------------------- + if ((state != GUI_STATE_DISABLED) && !guiLocked) + { + Vector2 mousePoint = GetMousePosition(); + + if (CheckCollisionPointRec(mousePoint, bounds) || + CheckCollisionPointRec(mousePoint, selector)) + { + if (IsMouseButtonDown(MOUSE_LEFT_BUTTON)) + { + state = GUI_STATE_PRESSED; + selector.x = mousePoint.x - selector.width/2; + + alpha = (mousePoint.x - bounds.x)/bounds.width; + if (alpha <= 0.0f) alpha = 0.0f; + if (alpha >= 1.0f) alpha = 1.0f; + //selector.x = bounds.x + (int)(((alpha - 0)/(100 - 0))*(bounds.width - 2*GuiGetStyle(SLIDER, BORDER_WIDTH))) - selector.width/2; + } + else state = GUI_STATE_FOCUSED; + } + } + //-------------------------------------------------------------------- + + // Draw control + //-------------------------------------------------------------------- + + // Draw alpha bar: checked background + if (state != GUI_STATE_DISABLED) + { + int checksX = bounds.width/COLORBARALPHA_CHECKED_SIZE; + int checksY = bounds.height/COLORBARALPHA_CHECKED_SIZE; + + for (int x = 0; x < checksX; x++) + { + for (int y = 0; y < checksY; y++) + { + Rectangle check = { bounds.x + x*COLORBARALPHA_CHECKED_SIZE, bounds.y + y*COLORBARALPHA_CHECKED_SIZE, COLORBARALPHA_CHECKED_SIZE, COLORBARALPHA_CHECKED_SIZE }; + GuiDrawRectangle(check, 0, BLANK, ((x + y)%2)? Fade(Fade(GetColor(GuiGetStyle(COLORPICKER, BORDER_COLOR_DISABLED)), 0.4f), guiAlpha) : Fade(Fade(GetColor(GuiGetStyle(COLORPICKER, BASE_COLOR_DISABLED)), 0.4f), guiAlpha)); + } + } + + DrawRectangleGradientEx(bounds, RAYGUI_CLITERAL(Color){ 255, 255, 255, 0 }, RAYGUI_CLITERAL(Color){ 255, 255, 255, 0 }, Fade(RAYGUI_CLITERAL(Color){ 0, 0, 0, 255 }, guiAlpha), Fade(RAYGUI_CLITERAL(Color){ 0, 0, 0, 255 }, guiAlpha)); + } + else DrawRectangleGradientEx(bounds, Fade(GetColor(GuiGetStyle(COLORPICKER, BASE_COLOR_DISABLED)), 0.1f), Fade(GetColor(GuiGetStyle(COLORPICKER, BASE_COLOR_DISABLED)), 0.1f), Fade(GetColor(GuiGetStyle(COLORPICKER, BORDER_COLOR_DISABLED)), guiAlpha), Fade(GetColor(GuiGetStyle(COLORPICKER, BORDER_COLOR_DISABLED)), guiAlpha)); + + GuiDrawRectangle(bounds, 1, Fade(GetColor(GuiGetStyle(COLORPICKER, BORDER + state*3)), guiAlpha), BLANK); + + // Draw alpha bar: selector + GuiDrawRectangle(selector, 0, BLANK, Fade(GetColor(GuiGetStyle(COLORPICKER, BORDER + state*3)), guiAlpha)); + //-------------------------------------------------------------------- + + return alpha; +} + +// Color Bar Hue control +// NOTE: Returns hue value normalized [0..1] +float GuiColorBarHue(Rectangle bounds, float hue) +{ + GuiControlState state = guiState; + Rectangle selector = { (float)bounds.x - GuiGetStyle(COLORPICKER, HUEBAR_SELECTOR_OVERFLOW), (float)bounds.y + hue/360.0f*bounds.height - GuiGetStyle(COLORPICKER, HUEBAR_SELECTOR_OVERFLOW), (float)bounds.width + GuiGetStyle(COLORPICKER, HUEBAR_SELECTOR_OVERFLOW)*2, (float)GuiGetStyle(COLORPICKER, HUEBAR_SELECTOR_HEIGHT) }; + + // Update control + //-------------------------------------------------------------------- + if ((state != GUI_STATE_DISABLED) && !guiLocked) + { + Vector2 mousePoint = GetMousePosition(); + + if (CheckCollisionPointRec(mousePoint, bounds) || + CheckCollisionPointRec(mousePoint, selector)) + { + if (IsMouseButtonDown(MOUSE_LEFT_BUTTON)) + { + state = GUI_STATE_PRESSED; + selector.y = mousePoint.y - selector.height/2; + + hue = (mousePoint.y - bounds.y)*360/bounds.height; + if (hue <= 0.0f) hue = 0.0f; + if (hue >= 359.0f) hue = 359.0f; + + } + else state = GUI_STATE_FOCUSED; + + /*if (IsKeyDown(KEY_UP)) + { + hue -= 2.0f; + if (hue <= 0.0f) hue = 0.0f; + } + else if (IsKeyDown(KEY_DOWN)) + { + hue += 2.0f; + if (hue >= 360.0f) hue = 360.0f; + }*/ + } + } + //-------------------------------------------------------------------- + + // Draw control + //-------------------------------------------------------------------- + if (state != GUI_STATE_DISABLED) + { + // Draw hue bar:color bars + DrawRectangleGradientV(bounds.x + GuiGetStyle(COLORPICKER, HUEBAR_SELECTOR_OVERFLOW)/2, bounds.y + GuiGetStyle(COLORPICKER, HUEBAR_SELECTOR_OVERFLOW)/2, bounds.width - GuiGetStyle(COLORPICKER, HUEBAR_SELECTOR_OVERFLOW), (int)bounds.height/6, Fade(RAYGUI_CLITERAL(Color){ 255,0,0,255 }, guiAlpha), Fade(RAYGUI_CLITERAL(Color){ 255,255,0,255 }, guiAlpha)); + DrawRectangleGradientV(bounds.x + GuiGetStyle(COLORPICKER, HUEBAR_SELECTOR_OVERFLOW)/2, bounds.y + (int)bounds.height/6 + GuiGetStyle(COLORPICKER, HUEBAR_SELECTOR_OVERFLOW)/2, bounds.width - GuiGetStyle(COLORPICKER, HUEBAR_SELECTOR_OVERFLOW), (int)bounds.height/6, Fade(RAYGUI_CLITERAL(Color){ 255,255,0,255 }, guiAlpha), Fade(RAYGUI_CLITERAL(Color){ 0,255,0,255 }, guiAlpha)); + DrawRectangleGradientV(bounds.x + GuiGetStyle(COLORPICKER, HUEBAR_SELECTOR_OVERFLOW)/2, bounds.y + 2*((int)bounds.height/6) + GuiGetStyle(COLORPICKER, HUEBAR_SELECTOR_OVERFLOW)/2, bounds.width - GuiGetStyle(COLORPICKER, HUEBAR_SELECTOR_OVERFLOW), (int)bounds.height/6, Fade(RAYGUI_CLITERAL(Color){ 0,255,0,255 }, guiAlpha), Fade(RAYGUI_CLITERAL(Color){ 0,255,255,255 }, guiAlpha)); + DrawRectangleGradientV(bounds.x + GuiGetStyle(COLORPICKER, HUEBAR_SELECTOR_OVERFLOW)/2, bounds.y + 3*((int)bounds.height/6) + GuiGetStyle(COLORPICKER, HUEBAR_SELECTOR_OVERFLOW)/2, bounds.width - GuiGetStyle(COLORPICKER, HUEBAR_SELECTOR_OVERFLOW), (int)bounds.height/6, Fade(RAYGUI_CLITERAL(Color){ 0,255,255,255 }, guiAlpha), Fade(RAYGUI_CLITERAL(Color){ 0,0,255,255 }, guiAlpha)); + DrawRectangleGradientV(bounds.x + GuiGetStyle(COLORPICKER, HUEBAR_SELECTOR_OVERFLOW)/2, bounds.y + 4*((int)bounds.height/6) + GuiGetStyle(COLORPICKER, HUEBAR_SELECTOR_OVERFLOW)/2, bounds.width - GuiGetStyle(COLORPICKER, HUEBAR_SELECTOR_OVERFLOW), (int)bounds.height/6, Fade(RAYGUI_CLITERAL(Color){ 0,0,255,255 }, guiAlpha), Fade(RAYGUI_CLITERAL(Color){ 255,0,255,255 }, guiAlpha)); + DrawRectangleGradientV(bounds.x + GuiGetStyle(COLORPICKER, HUEBAR_SELECTOR_OVERFLOW)/2, bounds.y + 5*((int)bounds.height/6) + GuiGetStyle(COLORPICKER, HUEBAR_SELECTOR_OVERFLOW)/2, bounds.width - GuiGetStyle(COLORPICKER, HUEBAR_SELECTOR_OVERFLOW), (int)bounds.height/6 - GuiGetStyle(COLORPICKER, HUEBAR_SELECTOR_OVERFLOW), Fade(RAYGUI_CLITERAL(Color){ 255,0,255,255 }, guiAlpha), Fade(RAYGUI_CLITERAL(Color){ 255,0,0,255 }, guiAlpha)); + } + else DrawRectangleGradientV(bounds.x, bounds.y, bounds.width, bounds.height, Fade(Fade(GetColor(GuiGetStyle(COLORPICKER, BASE_COLOR_DISABLED)), 0.1f), guiAlpha), Fade(GetColor(GuiGetStyle(COLORPICKER, BORDER_COLOR_DISABLED)), guiAlpha)); + + GuiDrawRectangle(bounds, 1, Fade(GetColor(GuiGetStyle(COLORPICKER, BORDER + state*3)), guiAlpha), BLANK); + + // Draw hue bar: selector + GuiDrawRectangle(selector, 0, BLANK, Fade(GetColor(GuiGetStyle(COLORPICKER, BORDER + state*3)), guiAlpha)); + //-------------------------------------------------------------------- + + return hue; +} + +// TODO: Color GuiColorBarSat() [WHITE->color] +// TODO: Color GuiColorBarValue() [BLACK->color], HSV / HSL +// TODO: float GuiColorBarLuminance() [BLACK->WHITE] + +// Color Picker control +// NOTE: It's divided in multiple controls: +// Color GuiColorPanel(Rectangle bounds, Color color) +// float GuiColorBarAlpha(Rectangle bounds, float alpha) +// float GuiColorBarHue(Rectangle bounds, float value) +// NOTE: bounds define GuiColorPanel() size +Color GuiColorPicker(Rectangle bounds, Color color) +{ + color = GuiColorPanel(bounds, color); + + Rectangle boundsHue = { (float)bounds.x + bounds.width + GuiGetStyle(COLORPICKER, HUEBAR_PADDING), (float)bounds.y, (float)GuiGetStyle(COLORPICKER, HUEBAR_WIDTH), (float)bounds.height }; + //Rectangle boundsAlpha = { bounds.x, bounds.y + bounds.height + GuiGetStyle(COLORPICKER, BARS_PADDING), bounds.width, GuiGetStyle(COLORPICKER, BARS_THICK) }; + + Vector3 hsv = ConvertRGBtoHSV(RAYGUI_CLITERAL(Vector3){ color.r/255.0f, color.g/255.0f, color.b/255.0f }); + hsv.x = GuiColorBarHue(boundsHue, hsv.x); + //color.a = (unsigned char)(GuiColorBarAlpha(boundsAlpha, (float)color.a/255.0f)*255.0f); + Vector3 rgb = ConvertHSVtoRGB(hsv); + color = RAYGUI_CLITERAL(Color){ (unsigned char)roundf(rgb.x*255.0f), (unsigned char)roundf(rgb.y*255.0f), (unsigned char)roundf(rgb.z*255.0f), color.a }; + + return color; +} + +// Message Box control +int GuiMessageBox(Rectangle bounds, const char *title, const char *message, const char *buttons) +{ + #define MESSAGEBOX_BUTTON_HEIGHT 24 + #define MESSAGEBOX_BUTTON_PADDING 10 + + int clicked = -1; // Returns clicked button from buttons list, 0 refers to closed window button + + int buttonsCount = 0; + const char **buttonsText = GuiTextSplit(buttons, &buttonsCount, NULL); + Rectangle buttonBounds = { 0 }; + buttonBounds.x = bounds.x + MESSAGEBOX_BUTTON_PADDING; + buttonBounds.y = bounds.y + bounds.height - MESSAGEBOX_BUTTON_HEIGHT - MESSAGEBOX_BUTTON_PADDING; + buttonBounds.width = (bounds.width - MESSAGEBOX_BUTTON_PADDING*(buttonsCount + 1))/buttonsCount; + buttonBounds.height = MESSAGEBOX_BUTTON_HEIGHT; + + Vector2 textSize = MeasureTextEx(guiFont, message, GuiGetStyle(DEFAULT, TEXT_SIZE), 1); + + Rectangle textBounds = { 0 }; + textBounds.x = bounds.x + bounds.width/2 - textSize.x/2; + textBounds.y = bounds.y + WINDOW_STATUSBAR_HEIGHT + (bounds.height - WINDOW_STATUSBAR_HEIGHT - MESSAGEBOX_BUTTON_HEIGHT - MESSAGEBOX_BUTTON_PADDING)/2 - textSize.y/2; + textBounds.width = textSize.x; + textBounds.height = textSize.y; + + // Draw control + //-------------------------------------------------------------------- + if (GuiWindowBox(bounds, title)) clicked = 0; + + int prevTextAlignment = GuiGetStyle(LABEL, TEXT_ALIGNMENT); + GuiSetStyle(LABEL, TEXT_ALIGNMENT, GUI_TEXT_ALIGN_CENTER); + GuiLabel(textBounds, message); + GuiSetStyle(LABEL, TEXT_ALIGNMENT, prevTextAlignment); + + prevTextAlignment = GuiGetStyle(BUTTON, TEXT_ALIGNMENT); + GuiSetStyle(BUTTON, TEXT_ALIGNMENT, GUI_TEXT_ALIGN_CENTER); + + for (int i = 0; i < buttonsCount; i++) + { + if (GuiButton(buttonBounds, buttonsText[i])) clicked = i + 1; + buttonBounds.x += (buttonBounds.width + MESSAGEBOX_BUTTON_PADDING); + } + + GuiSetStyle(BUTTON, TEXT_ALIGNMENT, prevTextAlignment); + //-------------------------------------------------------------------- + + return clicked; +} + +// Text Input Box control, ask for text +int GuiTextInputBox(Rectangle bounds, const char *title, const char *message, const char *buttons, char *text) +{ + #define TEXTINPUTBOX_BUTTON_HEIGHT 24 + #define TEXTINPUTBOX_BUTTON_PADDING 10 + #define TEXTINPUTBOX_HEIGHT 30 + + #define TEXTINPUTBOX_MAX_TEXT_LENGTH 256 + + // Used to enable text edit mode + // WARNING: No more than one GuiTextInputBox() should be open at the same time + static bool textEditMode = false; + + int btnIndex = -1; + + int buttonsCount = 0; + const char **buttonsText = GuiTextSplit(buttons, &buttonsCount, NULL); + Rectangle buttonBounds = { 0 }; + buttonBounds.x = bounds.x + TEXTINPUTBOX_BUTTON_PADDING; + buttonBounds.y = bounds.y + bounds.height - TEXTINPUTBOX_BUTTON_HEIGHT - TEXTINPUTBOX_BUTTON_PADDING; + buttonBounds.width = (bounds.width - TEXTINPUTBOX_BUTTON_PADDING*(buttonsCount + 1))/buttonsCount; + buttonBounds.height = TEXTINPUTBOX_BUTTON_HEIGHT; + + int messageInputHeight = bounds.height - WINDOW_STATUSBAR_HEIGHT - GuiGetStyle(STATUSBAR, BORDER_WIDTH) - TEXTINPUTBOX_BUTTON_HEIGHT - 2*TEXTINPUTBOX_BUTTON_PADDING; + + Rectangle textBounds = { 0 }; + if (message != NULL) + { + Vector2 textSize = MeasureTextEx(guiFont, message, GuiGetStyle(DEFAULT, TEXT_SIZE), 1); + + textBounds.x = bounds.x + bounds.width/2 - textSize.x/2; + textBounds.y = bounds.y + WINDOW_STATUSBAR_HEIGHT + messageInputHeight/4 - textSize.y/2; + textBounds.width = textSize.x; + textBounds.height = textSize.y; + } + + Rectangle textBoxBounds = { 0 }; + textBoxBounds.x = bounds.x + TEXTINPUTBOX_BUTTON_PADDING; + textBoxBounds.y = bounds.y + WINDOW_STATUSBAR_HEIGHT - TEXTINPUTBOX_HEIGHT/2; + if (message == NULL) textBoxBounds.y += messageInputHeight/2; + else textBoxBounds.y += (messageInputHeight/2 + messageInputHeight/4); + textBoxBounds.width = bounds.width - TEXTINPUTBOX_BUTTON_PADDING*2; + textBoxBounds.height = TEXTINPUTBOX_HEIGHT; + + // Draw control + //-------------------------------------------------------------------- + if (GuiWindowBox(bounds, title)) btnIndex = 0; + + // Draw message if available + if (message != NULL) + { + int prevTextAlignment = GuiGetStyle(LABEL, TEXT_ALIGNMENT); + GuiSetStyle(LABEL, TEXT_ALIGNMENT, GUI_TEXT_ALIGN_CENTER); + GuiLabel(textBounds, message); + GuiSetStyle(LABEL, TEXT_ALIGNMENT, prevTextAlignment); + } + + if (GuiTextBox(textBoxBounds, text, TEXTINPUTBOX_MAX_TEXT_LENGTH, textEditMode)) textEditMode = !textEditMode; + + int prevBtnTextAlignment = GuiGetStyle(BUTTON, TEXT_ALIGNMENT); + GuiSetStyle(BUTTON, TEXT_ALIGNMENT, GUI_TEXT_ALIGN_CENTER); + + for (int i = 0; i < buttonsCount; i++) + { + if (GuiButton(buttonBounds, buttonsText[i])) btnIndex = i + 1; + buttonBounds.x += (buttonBounds.width + MESSAGEBOX_BUTTON_PADDING); + } + + GuiSetStyle(BUTTON, TEXT_ALIGNMENT, prevBtnTextAlignment); + //-------------------------------------------------------------------- + + return btnIndex; +} + +// Grid control +// NOTE: Returns grid mouse-hover selected cell +// About drawing lines at subpixel spacing, simple put, not easy solution: +// https://stackoverflow.com/questions/4435450/2d-opengl-drawing-lines-that-dont-exactly-fit-pixel-raster +Vector2 GuiGrid(Rectangle bounds, float spacing, int subdivs) +{ + #if !defined(GRID_COLOR_ALPHA) + #define GRID_COLOR_ALPHA 0.15f // Grid lines alpha amount + #endif + + GuiControlState state = guiState; + Vector2 mousePoint = GetMousePosition(); + Vector2 currentCell = { -1, -1 }; + + int linesV = ((int)(bounds.width/spacing))*subdivs + 1; + int linesH = ((int)(bounds.height/spacing))*subdivs + 1; + + // Update control + //-------------------------------------------------------------------- + if ((state != GUI_STATE_DISABLED) && !guiLocked) + { + if (CheckCollisionPointRec(mousePoint, bounds)) + { + currentCell.x = (int)((mousePoint.x - bounds.x)/spacing); + currentCell.y = (int)((mousePoint.y - bounds.y)/spacing); + } + } + //-------------------------------------------------------------------- + + // Draw control + //-------------------------------------------------------------------- + switch (state) + { + case GUI_STATE_NORMAL: + { + if (subdivs > 0) + { + // Draw vertical grid lines + for (int i = 0; i < linesV; i++) + { + Rectangle lineV = { bounds.x + spacing * i / subdivs, bounds.y, 1, bounds.height }; + GuiDrawRectangle(lineV, 0, BLANK, ((i%subdivs) == 0) ? Fade(GetColor(GuiGetStyle(DEFAULT, LINE_COLOR)), GRID_COLOR_ALPHA * 4) : Fade(GetColor(GuiGetStyle(DEFAULT, LINE_COLOR)), GRID_COLOR_ALPHA)); + } + + // Draw horizontal grid lines + for (int i = 0; i < linesH; i++) + { + Rectangle lineH = { bounds.x, bounds.y + spacing * i / subdivs, bounds.width, 1 }; + GuiDrawRectangle(lineH, 0, BLANK, ((i%subdivs) == 0) ? Fade(GetColor(GuiGetStyle(DEFAULT, LINE_COLOR)), GRID_COLOR_ALPHA * 4) : Fade(GetColor(GuiGetStyle(DEFAULT, LINE_COLOR)), GRID_COLOR_ALPHA)); + } + } + } break; + default: break; + } + + return currentCell; +} + +//---------------------------------------------------------------------------------- +// Styles loading functions +//---------------------------------------------------------------------------------- + +// Load raygui style file (.rgs) +void GuiLoadStyle(const char *fileName) +{ + bool tryBinary = false; + + // Try reading the files as text file first + FILE *rgsFile = fopen(fileName, "rt"); + + if (rgsFile != NULL) + { + char buffer[256] = { 0 }; + fgets(buffer, 256, rgsFile); + + if (buffer[0] == '#') + { + int controlId = 0; + int propertyId = 0; + unsigned int propertyValue = 0; + + while (!feof(rgsFile)) + { + switch (buffer[0]) + { + case 'p': + { + // Style property: p + + sscanf(buffer, "p %d %d 0x%x", &controlId, &propertyId, &propertyValue); + + GuiSetStyle(controlId, propertyId, (int)propertyValue); + + } break; + case 'f': + { + // Style font: f + + int fontSize = 0; + char charmapFileName[256] = { 0 }; + char fontFileName[256] = { 0 }; + sscanf(buffer, "f %d %s %[^\n]s", &fontSize, charmapFileName, fontFileName); + + Font font = { 0 }; + + if (charmapFileName[0] != '0') + { + // Load characters from charmap file, + // expected '\n' separated list of integer values + char *charValues = LoadText(charmapFileName); + if (charValues != NULL) + { + int charsCount = 0; + const char **chars = TextSplit(charValues, '\n', &charsCount); + + int *values = (int *)RAYGUI_MALLOC(charsCount*sizeof(int)); + for (int i = 0; i < charsCount; i++) values[i] = TextToInteger(chars[i]); + + font = LoadFontEx(TextFormat("%s/%s", GetDirectoryPath(fileName), fontFileName), fontSize, values, charsCount); + + RAYGUI_FREE(values); + } + } + else font = LoadFontEx(TextFormat("%s/%s", GetDirectoryPath(fileName), fontFileName), fontSize, NULL, 0); + + if ((font.texture.id > 0) && (font.charsCount > 0)) GuiSetFont(font); + + } break; + default: break; + } + + fgets(buffer, 256, rgsFile); + } + } + else tryBinary = true; + + fclose(rgsFile); + } + + if (tryBinary) + { + rgsFile = fopen(fileName, "rb"); + + if (rgsFile == NULL) return; + + char signature[5] = ""; + short version = 0; + short reserved = 0; + int propertiesCount = 0; + + fread(signature, 1, 4, rgsFile); + fread(&version, 1, sizeof(short), rgsFile); + fread(&reserved, 1, sizeof(short), rgsFile); + fread(&propertiesCount, 1, sizeof(int), rgsFile); + + if ((signature[0] == 'r') && + (signature[1] == 'G') && + (signature[2] == 'S') && + (signature[3] == ' ')) + { + short controlId = 0; + short propertyId = 0; + int propertyValue = 0; + + for (int i = 0; i < propertiesCount; i++) + { + fread(&controlId, 1, sizeof(short), rgsFile); + fread(&propertyId, 1, sizeof(short), rgsFile); + fread(&propertyValue, 1, sizeof(int), rgsFile); + + if (controlId == 0) // DEFAULT control + { + // If a DEFAULT property is loaded, it is propagated to all controls + // NOTE: All DEFAULT properties should be defined first in the file + GuiSetStyle(0, (int)propertyId, propertyValue); + + if (propertyId < NUM_PROPS_DEFAULT) for (int i = 1; i < NUM_CONTROLS; i++) GuiSetStyle(i, (int)propertyId, propertyValue); + } + else GuiSetStyle((int)controlId, (int)propertyId, propertyValue); + } + + // Font loading is highly dependant on raylib API to load font data and image + // TODO: Find some mechanism to support it in standalone mode +#if !defined(RAYGUI_STANDALONE) + // Load custom font if available + int fontDataSize = 0; + fread(&fontDataSize, 1, sizeof(int), rgsFile); + + if (fontDataSize > 0) + { + Font font = { 0 }; + int fontType = 0; // 0-Normal, 1-SDF + Rectangle whiteRec = { 0 }; + + fread(&font.baseSize, 1, sizeof(int), rgsFile); + fread(&font.charsCount, 1, sizeof(int), rgsFile); + fread(&fontType, 1, sizeof(int), rgsFile); + + // Load font white rectangle + fread(&whiteRec, 1, sizeof(Rectangle), rgsFile); + + // Load font image parameters + int fontImageSize = 0; + fread(&fontImageSize, 1, sizeof(int), rgsFile); + + if (fontImageSize > 0) + { + Image imFont = { 0 }; + imFont.mipmaps = 1; + fread(&imFont.width, 1, sizeof(int), rgsFile); + fread(&imFont.height, 1, sizeof(int), rgsFile); + fread(&imFont.format, 1, sizeof(int), rgsFile); + + imFont.data = (unsigned char *)RAYGUI_MALLOC(fontImageSize); + fread(imFont.data, 1, fontImageSize, rgsFile); + + font.texture = LoadTextureFromImage(imFont); + + UnloadImage(imFont); + } + + // Load font recs data + font.recs = (Rectangle *)RAYGUI_CALLOC(font.charsCount, sizeof(Rectangle)); + for (int i = 0; i < font.charsCount; i++) fread(&font.recs[i], 1, sizeof(Rectangle), rgsFile); + + // Load font chars info data + font.chars = (CharInfo *)RAYGUI_CALLOC(font.charsCount, sizeof(CharInfo)); + for (int i = 0; i < font.charsCount; i++) + { + fread(&font.chars[i].value, 1, sizeof(int), rgsFile); + fread(&font.chars[i].offsetX, 1, sizeof(int), rgsFile); + fread(&font.chars[i].offsetY, 1, sizeof(int), rgsFile); + fread(&font.chars[i].advanceX, 1, sizeof(int), rgsFile); + } + + GuiSetFont(font); + + // Set font texture source rectangle to be used as white texture to draw shapes + // NOTE: This way, all gui can be draw using a single draw call + if ((whiteRec.width != 0) && (whiteRec.height != 0)) SetShapesTexture(font.texture, whiteRec); + } +#endif + } + + fclose(rgsFile); + } +} + +// Load style default over global style +void GuiLoadStyleDefault(void) +{ + // We set this variable first to avoid cyclic function calls + // when calling GuiSetStyle() and GuiGetStyle() + guiStyleLoaded = true; + + // Initialize default LIGHT style property values + GuiSetStyle(DEFAULT, BORDER_COLOR_NORMAL, 0x838383ff); + GuiSetStyle(DEFAULT, BASE_COLOR_NORMAL, 0xc9c9c9ff); + GuiSetStyle(DEFAULT, TEXT_COLOR_NORMAL, 0x686868ff); + GuiSetStyle(DEFAULT, BORDER_COLOR_FOCUSED, 0x5bb2d9ff); + GuiSetStyle(DEFAULT, BASE_COLOR_FOCUSED, 0xc9effeff); + GuiSetStyle(DEFAULT, TEXT_COLOR_FOCUSED, 0x6c9bbcff); + GuiSetStyle(DEFAULT, BORDER_COLOR_PRESSED, 0x0492c7ff); + GuiSetStyle(DEFAULT, BASE_COLOR_PRESSED, 0x97e8ffff); + GuiSetStyle(DEFAULT, TEXT_COLOR_PRESSED, 0x368bafff); + GuiSetStyle(DEFAULT, BORDER_COLOR_DISABLED, 0xb5c1c2ff); + GuiSetStyle(DEFAULT, BASE_COLOR_DISABLED, 0xe6e9e9ff); + GuiSetStyle(DEFAULT, TEXT_COLOR_DISABLED, 0xaeb7b8ff); + GuiSetStyle(DEFAULT, BORDER_WIDTH, 1); // WARNING: Some controls use other values + GuiSetStyle(DEFAULT, TEXT_PADDING, 0); // WARNING: Some controls use other values + GuiSetStyle(DEFAULT, TEXT_ALIGNMENT, GUI_TEXT_ALIGN_CENTER); // WARNING: Some controls use other values + + // Initialize control-specific property values + // NOTE: Those properties are in default list but require specific values by control type + GuiSetStyle(LABEL, TEXT_ALIGNMENT, GUI_TEXT_ALIGN_LEFT); + GuiSetStyle(BUTTON, BORDER_WIDTH, 2); + GuiSetStyle(SLIDER, TEXT_PADDING, 5); + GuiSetStyle(CHECKBOX, TEXT_PADDING, 5); + GuiSetStyle(CHECKBOX, TEXT_ALIGNMENT, GUI_TEXT_ALIGN_RIGHT); + GuiSetStyle(TEXTBOX, TEXT_PADDING, 5); + GuiSetStyle(TEXTBOX, TEXT_ALIGNMENT, GUI_TEXT_ALIGN_LEFT); + GuiSetStyle(VALUEBOX, TEXT_PADDING, 4); + GuiSetStyle(VALUEBOX, TEXT_ALIGNMENT, GUI_TEXT_ALIGN_LEFT); + GuiSetStyle(SPINNER, TEXT_PADDING, 4); + GuiSetStyle(SPINNER, TEXT_ALIGNMENT, GUI_TEXT_ALIGN_LEFT); + GuiSetStyle(STATUSBAR, TEXT_PADDING, 6); + GuiSetStyle(STATUSBAR, TEXT_ALIGNMENT, GUI_TEXT_ALIGN_LEFT); + + // Initialize extended property values + // NOTE: By default, extended property values are initialized to 0 + GuiSetStyle(DEFAULT, TEXT_SIZE, 10); // DEFAULT, shared by all controls + GuiSetStyle(DEFAULT, TEXT_SPACING, 1); // DEFAULT, shared by all controls + GuiSetStyle(DEFAULT, LINE_COLOR, 0x90abb5ff); // DEFAULT specific property + GuiSetStyle(DEFAULT, BACKGROUND_COLOR, 0xf5f5f5ff); // DEFAULT specific property + GuiSetStyle(TOGGLE, GROUP_PADDING, 2); + GuiSetStyle(SLIDER, SLIDER_WIDTH, 15); + GuiSetStyle(SLIDER, SLIDER_PADDING, 1); + GuiSetStyle(PROGRESSBAR, PROGRESS_PADDING, 1); + GuiSetStyle(CHECKBOX, CHECK_PADDING, 1); + GuiSetStyle(COMBOBOX, COMBO_BUTTON_WIDTH, 30); + GuiSetStyle(COMBOBOX, COMBO_BUTTON_PADDING, 2); + GuiSetStyle(DROPDOWNBOX, ARROW_PADDING, 16); + GuiSetStyle(DROPDOWNBOX, DROPDOWN_ITEMS_PADDING, 2); + GuiSetStyle(TEXTBOX, TEXT_LINES_PADDING, 5); + GuiSetStyle(TEXTBOX, TEXT_INNER_PADDING, 4); + GuiSetStyle(TEXTBOX, COLOR_SELECTED_FG, 0xf0fffeff); + GuiSetStyle(TEXTBOX, COLOR_SELECTED_BG, 0x839affe0); + GuiSetStyle(SPINNER, SPIN_BUTTON_WIDTH, 20); + GuiSetStyle(SPINNER, SPIN_BUTTON_PADDING, 2); + GuiSetStyle(SCROLLBAR, BORDER_WIDTH, 0); + GuiSetStyle(SCROLLBAR, ARROWS_VISIBLE, 0); + GuiSetStyle(SCROLLBAR, ARROWS_SIZE, 6); + GuiSetStyle(SCROLLBAR, SCROLL_SLIDER_PADDING, 0); + GuiSetStyle(SCROLLBAR, SCROLL_SLIDER_SIZE, 16); + GuiSetStyle(SCROLLBAR, SCROLL_PADDING, 0); + GuiSetStyle(SCROLLBAR, SCROLL_SPEED, 10); + GuiSetStyle(LISTVIEW, LIST_ITEMS_HEIGHT, 0x1e); + GuiSetStyle(LISTVIEW, LIST_ITEMS_PADDING, 2); + GuiSetStyle(LISTVIEW, SCROLLBAR_WIDTH, 10); + GuiSetStyle(LISTVIEW, SCROLLBAR_SIDE, SCROLLBAR_RIGHT_SIDE); + GuiSetStyle(COLORPICKER, COLOR_SELECTOR_SIZE, 6); + GuiSetStyle(COLORPICKER, HUEBAR_WIDTH, 0x14); + GuiSetStyle(COLORPICKER, HUEBAR_PADDING, 0xa); + GuiSetStyle(COLORPICKER, HUEBAR_SELECTOR_HEIGHT, 6); + GuiSetStyle(COLORPICKER, HUEBAR_SELECTOR_OVERFLOW, 2); + + guiFont = GetFontDefault(); // Initialize default font +} + +// Get text with icon id prepended +// NOTE: Useful to add icons by name id (enum) instead of +// a number that can change between ricon versions +const char *GuiIconText(int iconId, const char *text) +{ +#if defined(RAYGUI_SUPPORT_ICONS) + static char buffer[1024] = { 0 }; + memset(buffer, 0, 1024); + + sprintf(buffer, "#%03i#", iconId); + + if (text != NULL) + { + for (int i = 5; i < 1024; i++) + { + buffer[i] = text[i - 5]; + if (text[i - 5] == '\0') break; + } + } + + return buffer; +#else + return NULL; +#endif +} + +#if defined(RAYGUI_SUPPORT_ICONS) + +// Get full icons data pointer +unsigned int *GuiGetIcons(void) { return guiIcons; } + +// Load raygui icons file (.rgi) +// NOTE: In case nameIds are required, they can be requested with loadIconsName, +// they are returned as a guiIconsName[iconsCount][RICON_MAX_NAME_LENGTH], +// guiIconsName[]][] memory should be manually freed! +char **GuiLoadIcons(const char *fileName, bool loadIconsName) +{ + // Style File Structure (.rgi) + // ------------------------------------------------------ + // Offset | Size | Type | Description + // ------------------------------------------------------ + // 0 | 4 | char | Signature: "rGI " + // 4 | 2 | short | Version: 100 + // 6 | 2 | short | reserved + + // 8 | 2 | short | Num icons (N) + // 10 | 2 | short | Icons size (Options: 16, 32, 64) (S) + + // Icons name id (32 bytes per name id) + // foreach (icon) + // { + // 12+32*i | 32 | char | Icon NameId + // } + + // Icons data: One bit per pixel, stored as unsigned int array (depends on icon size) + // S*S pixels/32bit per unsigned int = K unsigned int per icon + // foreach (icon) + // { + // ... | K | unsigned int | Icon Data + // } + + FILE *rgiFile = fopen(fileName, "rb"); + + char **guiIconsName = NULL; + + if (rgiFile != NULL) + { + char signature[5] = ""; + short version = 0; + short reserved = 0; + short iconsCount = 0; + short iconsSize = 0; + + fread(signature, 1, 4, rgiFile); + fread(&version, 1, sizeof(short), rgiFile); + fread(&reserved, 1, sizeof(short), rgiFile); + fread(&iconsCount, 1, sizeof(short), rgiFile); + fread(&iconsSize, 1, sizeof(short), rgiFile); + + if ((signature[0] == 'r') && + (signature[1] == 'G') && + (signature[2] == 'I') && + (signature[3] == ' ')) + { + if (loadIconsName) + { + guiIconsName = (char **)RAYGUI_MALLOC(iconsCount*sizeof(char **)); + for (int i = 0; i < iconsCount; i++) + { + guiIconsName[i] = (char *)RAYGUI_MALLOC(RICON_MAX_NAME_LENGTH); + fread(guiIconsName[i], 32, 1, rgiFile); + } + } + + // Read icons data directly over guiIcons data array + fread(guiIcons, iconsCount*(iconsSize*iconsSize/32), sizeof(unsigned int), rgiFile); + } + + fclose(rgiFile); + } + + return guiIconsName; +} + +// Draw selected icon using rectangles pixel-by-pixel +void GuiDrawIcon(int iconId, Vector2 position, int pixelSize, Color color) +{ + #define BIT_CHECK(a,b) ((a) & (1<<(b))) + + for (int i = 0, y = 0; i < RICON_SIZE*RICON_SIZE/32; i++) + { + for (int k = 0; k < 32; k++) + { + if (BIT_CHECK(guiIcons[iconId*RICON_DATA_ELEMENTS + i], k)) + { + #if !defined(RAYGUI_STANDALONE) + DrawRectangle(position.x + (k%RICON_SIZE)*pixelSize, position.y + y*pixelSize, pixelSize, pixelSize, color); + #endif + } + + if ((k == 15) || (k == 31)) y++; + } + } +} + +// Get icon bit data +// NOTE: Bit data array grouped as unsigned int (ICON_SIZE*ICON_SIZE/32 elements) +unsigned int *GuiGetIconData(int iconId) +{ + static unsigned int iconData[RICON_DATA_ELEMENTS] = { 0 }; + memset(iconData, 0, RICON_DATA_ELEMENTS*sizeof(unsigned int)); + + if (iconId < RICON_MAX_ICONS) memcpy(iconData, &guiIcons[iconId*RICON_DATA_ELEMENTS], RICON_DATA_ELEMENTS*sizeof(unsigned int)); + + return iconData; +} + +// Set icon bit data +// NOTE: Data must be provided as unsigned int array (ICON_SIZE*ICON_SIZE/32 elements) +void GuiSetIconData(int iconId, unsigned int *data) +{ + if (iconId < RICON_MAX_ICONS) memcpy(&guiIcons[iconId*RICON_DATA_ELEMENTS], data, RICON_DATA_ELEMENTS*sizeof(unsigned int)); +} + +// Set icon pixel value +void GuiSetIconPixel(int iconId, int x, int y) +{ + #define BIT_SET(a,b) ((a) |= (1<<(b))) + + // This logic works for any RICON_SIZE pixels icons, + // For example, in case of 16x16 pixels, every 2 lines fit in one unsigned int data element + BIT_SET(guiIcons[iconId*RICON_DATA_ELEMENTS + y/(sizeof(unsigned int)*8/RICON_SIZE)], x + (y%(sizeof(unsigned int)*8/RICON_SIZE)*RICON_SIZE)); +} + +// Clear icon pixel value +void GuiClearIconPixel(int iconId, int x, int y) +{ + #define BIT_CLEAR(a,b) ((a) &= ~((1)<<(b))) + + // This logic works for any RICON_SIZE pixels icons, + // For example, in case of 16x16 pixels, every 2 lines fit in one unsigned int data element + BIT_CLEAR(guiIcons[iconId*RICON_DATA_ELEMENTS + y/(sizeof(unsigned int)*8/RICON_SIZE)], x + (y%(sizeof(unsigned int)*8/RICON_SIZE)*RICON_SIZE)); +} + +// Check icon pixel value +bool GuiCheckIconPixel(int iconId, int x, int y) +{ + #define BIT_CHECK(a,b) ((a) & (1<<(b))) + + return (BIT_CHECK(guiIcons[iconId*8 + y/2], x + (y%2*16))); +} +#endif // RAYGUI_SUPPORT_ICONS + +//---------------------------------------------------------------------------------- +// Module specific Functions Definition +//---------------------------------------------------------------------------------- +// Gui get text width using default font +static int GetTextWidth(const char *text) +{ + Vector2 size = { 0 }; + + if ((text != NULL) && (text[0] != '\0')) size = MeasureTextEx(guiFont, text, GuiGetStyle(DEFAULT, TEXT_SIZE), GuiGetStyle(DEFAULT, TEXT_SPACING)); + + // TODO: Consider text icon width here??? + + return (int)size.x; +} + +// Get text bounds considering control bounds +static Rectangle GetTextBounds(int control, Rectangle bounds) +{ + Rectangle textBounds = bounds; + + textBounds.x = bounds.x + GuiGetStyle(control, BORDER_WIDTH); + textBounds.y = bounds.y + GuiGetStyle(control, BORDER_WIDTH); + textBounds.width = bounds.width - 2*GuiGetStyle(control, BORDER_WIDTH); + textBounds.height = bounds.height - 2*GuiGetStyle(control, BORDER_WIDTH); + + // Consider TEXT_PADDING properly, depends on control type and TEXT_ALIGNMENT + switch (control) + { + case COMBOBOX: bounds.width -= (GuiGetStyle(control, COMBO_BUTTON_WIDTH) + GuiGetStyle(control, COMBO_BUTTON_PADDING)); break; + case VALUEBOX: break; // NOTE: ValueBox text value always centered, text padding applies to label + default: + { + if (GuiGetStyle(control, TEXT_ALIGNMENT) == GUI_TEXT_ALIGN_RIGHT) textBounds.x -= GuiGetStyle(control, TEXT_PADDING); + else textBounds.x += GuiGetStyle(control, TEXT_PADDING); + } break; + } + + // TODO: Special cases (no label): COMBOBOX, DROPDOWNBOX, LISTVIEW (scrollbar?) + // More special cases (label side): CHECKBOX, SLIDER, VALUEBOX, SPINNER + + return textBounds; +} + +// Get text icon if provided and move text cursor +// NOTE: We support up to 999 values for iconId +static const char *GetTextIcon(const char *text, int *iconId) +{ +#if defined(RAYGUI_SUPPORT_ICONS) + *iconId = -1; + if (text[0] == '#') // Maybe we have an icon! + { + char iconValue[4] = { 0 }; // Maximum length for icon value: 3 digits + '\0' + + int pos = 1; + while ((pos < 4) && (text[pos] >= '0') && (text[pos] <= '9')) + { + iconValue[pos - 1] = text[pos]; + pos++; + } + + if (text[pos] == '#') + { + *iconId = TextToInteger(iconValue); + + // Move text pointer after icon + // WARNING: If only icon provided, it could point to EOL character! + if (*iconId >= 0) text += (pos + 1); + } + } +#endif + + return text; +} + +// Gui draw text using default font +static void GuiDrawText(const char *text, Rectangle bounds, int alignment, Color tint) +{ + #define TEXT_VALIGN_PIXEL_OFFSET(h) ((int)h%2) // Vertical alignment for pixel perfect + + if ((text != NULL) && (text[0] != '\0')) + { + int iconId = 0; + text = GetTextIcon(text, &iconId); // Check text for icon and move cursor + + // Get text position depending on alignment and iconId + //--------------------------------------------------------------------------------- + #define ICON_TEXT_PADDING 4 + + Vector2 position = { bounds.x, bounds.y }; + + // NOTE: We get text size after icon been processed + int textWidth = GetTextWidth(text); + int textHeight = GuiGetStyle(DEFAULT, TEXT_SIZE); + +#if defined(RAYGUI_SUPPORT_ICONS) + if (iconId >= 0) + { + textWidth += RICON_SIZE; + + // WARNING: If only icon provided, text could be pointing to eof character! + if ((text != NULL) && (text[0] != '\0')) textWidth += ICON_TEXT_PADDING; + } +#endif + // Check guiTextAlign global variables + switch (alignment) + { + case GUI_TEXT_ALIGN_LEFT: + { + position.x = bounds.x; + position.y = bounds.y + bounds.height/2 - textHeight/2 + TEXT_VALIGN_PIXEL_OFFSET(bounds.height); + } break; + case GUI_TEXT_ALIGN_CENTER: + { + position.x = bounds.x + bounds.width/2 - textWidth/2; + position.y = bounds.y + bounds.height/2 - textHeight/2 + TEXT_VALIGN_PIXEL_OFFSET(bounds.height); + } break; + case GUI_TEXT_ALIGN_RIGHT: + { + position.x = bounds.x + bounds.width - textWidth; + position.y = bounds.y + bounds.height/2 - textHeight/2 + TEXT_VALIGN_PIXEL_OFFSET(bounds.height); + } break; + default: break; + } + + // NOTE: Make sure we get pixel-perfect coordinates, + // In case of decimals we got weird text positioning + position.x = (float)((int)position.x); + position.y = (float)((int)position.y); + //--------------------------------------------------------------------------------- + + // Draw text (with icon if available) + //--------------------------------------------------------------------------------- +#if defined(RAYGUI_SUPPORT_ICONS) + if (iconId >= 0) + { + // NOTE: We consider icon height, probably different than text size + GuiDrawIcon(iconId, RAYGUI_CLITERAL(Vector2){ position.x, bounds.y + bounds.height/2 - RICON_SIZE/2 + TEXT_VALIGN_PIXEL_OFFSET(bounds.height) }, 1, tint); + position.x += (RICON_SIZE + ICON_TEXT_PADDING); + } +#endif + DrawTextEx(guiFont, text, position, GuiGetStyle(DEFAULT, TEXT_SIZE), GuiGetStyle(DEFAULT, TEXT_SPACING), tint); + //--------------------------------------------------------------------------------- + } +} + +// Gui draw rectangle using default raygui plain style with borders +static void GuiDrawRectangle(Rectangle rec, int borderWidth, Color borderColor, Color color) +{ + if (color.a > 0) + { + // Draw rectangle filled with color + DrawRectangle(rec.x, rec.y, rec.width, rec.height, color); + } + + if (borderWidth > 0) + { + // Draw rectangle border lines with color + DrawRectangle(rec.x, rec.y, rec.width, borderWidth, borderColor); + DrawRectangle(rec.x, rec.y + borderWidth, borderWidth, rec.height - 2*borderWidth, borderColor); + DrawRectangle(rec.x + rec.width - borderWidth, rec.y + borderWidth, borderWidth, rec.height - 2*borderWidth, borderColor); + DrawRectangle(rec.x, rec.y + rec.height - borderWidth, rec.width, borderWidth, borderColor); + } + + // TODO: For n-patch-based style we would need: [state] and maybe [control] + // In this case all controls drawing logic should be moved to this function... I don't like it... +} + +// Draw tooltip relatively to bounds +static void GuiDrawTooltip(Rectangle bounds) +{ + //static int tooltipFramesCounter = 0; // Not possible gets reseted at second function call! + + if (guiTooltipEnabled && (guiTooltip != NULL) && CheckCollisionPointRec(GetMousePosition(), bounds)) + { + Vector2 mousePosition = GetMousePosition(); + Vector2 textSize = MeasureTextEx(guiFont, guiTooltip, GuiGetStyle(DEFAULT, TEXT_SIZE), GuiGetStyle(DEFAULT, TEXT_SPACING)); + Rectangle tooltipBounds = { mousePosition.x, mousePosition.y, textSize.x + 20, textSize.y*2 }; + + GuiDrawRectangle(tooltipBounds, 1, Fade(GetColor(GuiGetStyle(DEFAULT, LINE_COLOR)), guiAlpha), Fade(GetColor(GuiGetStyle(DEFAULT, BACKGROUND_COLOR)), guiAlpha)); + + tooltipBounds.x += 10; + GuiLabel(tooltipBounds, guiTooltip); + } +} + +// Split controls text into multiple strings +// Also check for multiple columns (required by GuiToggleGroup()) +static const char **GuiTextSplit(const char *text, int *count, int *textRow) +{ + // NOTE: Current implementation returns a copy of the provided string with '\0' (string end delimiter) + // inserted between strings defined by "delimiter" parameter. No memory is dynamically allocated, + // all used memory is static... it has some limitations: + // 1. Maximum number of possible split strings is set by TEXTSPLIT_MAX_TEXT_ELEMENTS + // 2. Maximum size of text to split is TEXTSPLIT_MAX_TEXT_LENGTH + // NOTE: Those definitions could be externally provided if required + + #if !defined(TEXTSPLIT_MAX_TEXT_LENGTH) + #define TEXTSPLIT_MAX_TEXT_LENGTH 1024 + #endif + + #if !defined(TEXTSPLIT_MAX_TEXT_ELEMENTS) + #define TEXTSPLIT_MAX_TEXT_ELEMENTS 128 + #endif + + static const char *result[TEXTSPLIT_MAX_TEXT_ELEMENTS] = { NULL }; + static char buffer[TEXTSPLIT_MAX_TEXT_LENGTH] = { 0 }; + memset(buffer, 0, TEXTSPLIT_MAX_TEXT_LENGTH); + + result[0] = buffer; + int counter = 1; + + if (textRow != NULL) textRow[0] = 0; + + // Count how many substrings we have on text and point to every one + for (int i = 0; i < TEXTSPLIT_MAX_TEXT_LENGTH; i++) + { + buffer[i] = text[i]; + if (buffer[i] == '\0') break; + else if ((buffer[i] == ';') || (buffer[i] == '\n')) + { + result[counter] = buffer + i + 1; + + if (textRow != NULL) + { + if (buffer[i] == '\n') textRow[counter] = textRow[counter - 1] + 1; + else textRow[counter] = textRow[counter - 1]; + } + + buffer[i] = '\0'; // Set an end of string at this point + + counter++; + if (counter == TEXTSPLIT_MAX_TEXT_ELEMENTS) break; + } + } + + *count = counter; + + return result; +} + +// Convert color data from RGB to HSV +// NOTE: Color data should be passed normalized +static Vector3 ConvertRGBtoHSV(Vector3 rgb) +{ + Vector3 hsv = { 0 }; + float min = 0.0f; + float max = 0.0f; + float delta = 0.0f; + + min = (rgb.x < rgb.y)? rgb.x : rgb.y; + min = (min < rgb.z)? min : rgb.z; + + max = (rgb.x > rgb.y)? rgb.x : rgb.y; + max = (max > rgb.z)? max : rgb.z; + + hsv.z = max; // Value + delta = max - min; + + if (delta < 0.00001f) + { + hsv.y = 0.0f; + hsv.x = 0.0f; // Undefined, maybe NAN? + return hsv; + } + + if (max > 0.0f) + { + // NOTE: If max is 0, this divide would cause a crash + hsv.y = (delta/max); // Saturation + } + else + { + // NOTE: If max is 0, then r = g = b = 0, s = 0, h is undefined + hsv.y = 0.0f; + hsv.x = 0.0f; // Undefined, maybe NAN? + return hsv; + } + + // NOTE: Comparing float values could not work properly + if (rgb.x >= max) hsv.x = (rgb.y - rgb.z)/delta; // Between yellow & magenta + else + { + if (rgb.y >= max) hsv.x = 2.0f + (rgb.z - rgb.x)/delta; // Between cyan & yellow + else hsv.x = 4.0f + (rgb.x - rgb.y)/delta; // Between magenta & cyan + } + + hsv.x *= 60.0f; // Convert to degrees + + if (hsv.x < 0.0f) hsv.x += 360.0f; + + return hsv; +} + +// Convert color data from HSV to RGB +// NOTE: Color data should be passed normalized +static Vector3 ConvertHSVtoRGB(Vector3 hsv) +{ + Vector3 rgb = { 0 }; + float hh = 0.0f, p = 0.0f, q = 0.0f, t = 0.0f, ff = 0.0f; + long i = 0; + + // NOTE: Comparing float values could not work properly + if (hsv.y <= 0.0f) + { + rgb.x = hsv.z; + rgb.y = hsv.z; + rgb.z = hsv.z; + return rgb; + } + + hh = hsv.x; + if (hh >= 360.0f) hh = 0.0f; + hh /= 60.0f; + + i = (long)hh; + ff = hh - i; + p = hsv.z*(1.0f - hsv.y); + q = hsv.z*(1.0f - (hsv.y*ff)); + t = hsv.z*(1.0f - (hsv.y*(1.0f - ff))); + + switch (i) + { + case 0: + { + rgb.x = hsv.z; + rgb.y = t; + rgb.z = p; + } break; + case 1: + { + rgb.x = q; + rgb.y = hsv.z; + rgb.z = p; + } break; + case 2: + { + rgb.x = p; + rgb.y = hsv.z; + rgb.z = t; + } break; + case 3: + { + rgb.x = p; + rgb.y = q; + rgb.z = hsv.z; + } break; + case 4: + { + rgb.x = t; + rgb.y = p; + rgb.z = hsv.z; + } break; + case 5: + default: + { + rgb.x = hsv.z; + rgb.y = p; + rgb.z = q; + } break; + } + + return rgb; +} + +#if defined(RAYGUI_STANDALONE) +// Returns a Color struct from hexadecimal value +static Color GetColor(int hexValue) +{ + Color color; + + color.r = (unsigned char)(hexValue >> 24) & 0xFF; + color.g = (unsigned char)(hexValue >> 16) & 0xFF; + color.b = (unsigned char)(hexValue >> 8) & 0xFF; + color.a = (unsigned char)hexValue & 0xFF; + + return color; +} + +// Returns hexadecimal value for a Color +static int ColorToInt(Color color) +{ + return (((int)color.r << 24) | ((int)color.g << 16) | ((int)color.b << 8) | (int)color.a); +} + +// Check if point is inside rectangle +static bool CheckCollisionPointRec(Vector2 point, Rectangle rec) +{ + bool collision = false; + + if ((point.x >= rec.x) && (point.x <= (rec.x + rec.width)) && + (point.y >= rec.y) && (point.y <= (rec.y + rec.height))) collision = true; + + return collision; +} + +// Color fade-in or fade-out, alpha goes from 0.0f to 1.0f +static Color Fade(Color color, float alpha) +{ + if (alpha < 0.0f) alpha = 0.0f; + else if (alpha > 1.0f) alpha = 1.0f; + + Color result = { color.r, color.g, color.b, (unsigned char)(255.0f*alpha) }; + + return result; +} + +// Formatting of text with variables to 'embed' +static const char *TextFormat(const char *text, ...) +{ + #define MAX_FORMATTEXT_LENGTH 64 + + static char buffer[MAX_FORMATTEXT_LENGTH]; + + va_list args; + va_start(args, text); + vsprintf(buffer, text, args); + va_end(args); + + return buffer; +} + +// Draw rectangle with vertical gradient fill color +// NOTE: This function is only used by GuiColorPicker() +static void DrawRectangleGradientV(int posX, int posY, int width, int height, Color color1, Color color2) +{ + Rectangle bounds = { (float)posX, (float)posY, (float)width, (float)height }; + DrawRectangleGradientEx(bounds, color1, color2, color2, color1); +} + +#define TEXTSPLIT_MAX_TEXT_BUFFER_LENGTH 1024 // Size of static buffer: TextSplit() +#define TEXTSPLIT_MAX_SUBSTRINGS_COUNT 128 // Size of static pointers array: TextSplit() + + +// Split string into multiple strings +const char **TextSplit(const char *text, char delimiter, int *count) +{ + // NOTE: Current implementation returns a copy of the provided string with '\0' (string end delimiter) + // inserted between strings defined by "delimiter" parameter. No memory is dynamically allocated, + // all used memory is static... it has some limitations: + // 1. Maximum number of possible split strings is set by TEXTSPLIT_MAX_SUBSTRINGS_COUNT + // 2. Maximum size of text to split is TEXTSPLIT_MAX_TEXT_BUFFER_LENGTH + + static const char *result[TEXTSPLIT_MAX_SUBSTRINGS_COUNT] = { NULL }; + static char buffer[TEXTSPLIT_MAX_TEXT_BUFFER_LENGTH] = { 0 }; + memset(buffer, 0, TEXTSPLIT_MAX_TEXT_BUFFER_LENGTH); + + result[0] = buffer; + int counter = 0; + + if (text != NULL) + { + counter = 1; + + // Count how many substrings we have on text and point to every one + for (int i = 0; i < TEXTSPLIT_MAX_TEXT_BUFFER_LENGTH; i++) + { + buffer[i] = text[i]; + if (buffer[i] == '\0') break; + else if (buffer[i] == delimiter) + { + buffer[i] = '\0'; // Set an end of string at this point + result[counter] = buffer + i + 1; + counter++; + + if (counter == TEXTSPLIT_MAX_SUBSTRINGS_COUNT) break; + } + } + } + + *count = counter; + return result; +} + +// Get integer value from text +// NOTE: This function replaces atoi() [stdlib.h] +static int TextToInteger(const char *text) +{ + int value = 0; + int sign = 1; + + if ((text[0] == '+') || (text[0] == '-')) + { + if (text[0] == '-') sign = -1; + text++; + } + + for (int i = 0; ((text[i] >= '0') && (text[i] <= '9')); ++i) value = value*10 + (int)(text[i] - '0'); + + return value*sign; +} + +// Encode codepoint into utf8 text (char array length returned as parameter) +static const char *CodepointToUtf8(int codepoint, int *byteLength) +{ + static char utf8[6] = { 0 }; + int length = 0; + + if (codepoint <= 0x7f) + { + utf8[0] = (char)codepoint; + length = 1; + } + else if (codepoint <= 0x7ff) + { + utf8[0] = (char)(((codepoint >> 6) & 0x1f) | 0xc0); + utf8[1] = (char)((codepoint & 0x3f) | 0x80); + length = 2; + } + else if (codepoint <= 0xffff) + { + utf8[0] = (char)(((codepoint >> 12) & 0x0f) | 0xe0); + utf8[1] = (char)(((codepoint >> 6) & 0x3f) | 0x80); + utf8[2] = (char)((codepoint & 0x3f) | 0x80); + length = 3; + } + else if (codepoint <= 0x10ffff) + { + utf8[0] = (char)(((codepoint >> 18) & 0x07) | 0xf0); + utf8[1] = (char)(((codepoint >> 12) & 0x3f) | 0x80); + utf8[2] = (char)(((codepoint >> 6) & 0x3f) | 0x80); + utf8[3] = (char)((codepoint & 0x3f) | 0x80); + length = 4; + } + + *byteLength = length; + + return utf8; +} +#endif // RAYGUI_STANDALONE + +#endif // RAYGUI_IMPLEMENTATION