This commit is contained in:
IXtreme 2024-12-19 20:29:25 -05:00
commit 0135d84443
44 changed files with 19813 additions and 0 deletions

104
Makefile Normal file
View file

@ -0,0 +1,104 @@
#STATIC/DYNAMIC
#LIB_MODE = STATIC
LIB_MODE = DYNAMIC
# BUILD/DYN_LIBRARY
#IMGUI_MODE = BUILD
IMGUI_MODE = DYN_LIBRARY
CC = gcc
CXX = g++
ASSET_PREFIX = assets/
SRC_DIR = src
OBJ_DIR = obj
BIN_DIR = bin
LIB_DIR = lib
STATIC_INCLUDE_DIR = include
CPPFLAGS = -Isrc/imgui -g -D ASSET_DIR=\"$(ASSET_PREFIX)\"
CFLAGS = -g -D ASSET_DIR=\"$(ASSET_PREFIX)\"
LDFLAGS = -g
#global LDLIBS
LDLIBS += -L lib/
#LDLIBS += -L lib_web/
LD_DYNAMIC_LIBS = -lraylib -lsdbus-c++ -lmagic #only enable if dynamic mode
LD_STATIC_LIBS = -l:libraylib.a #only enable if static mode
EXTRA_DIRS = $(OBJ_DIR)/rlImGui
EXE = $(BIN_DIR)/main
#WEBMODE
#CC = emcc
#CXX = em++
#SET ALL TO STATIC, have web version of libraylib.a in libs
#ensure glfw is enable
#some tinkering may be requiresd to get this working, just make sure
#raylib has ES3 on (need to mod make file)
#LDFLAGS += -s TOTAL_MEMORY=268435456 -s USE_GLFW=3 -sMIN_WEBGL_VERSION=2 -s FULL_ES3 -s ASYNCIFY
#EXE = $(BIN_DIR)/main.html
C_SRC += $(wildcard $(SRC_DIR)/*.c) #GET LIST OF ALL C FILES
CPP_SRC += $(wildcard $(SRC_DIR)/*.cpp) #GET LIST OF ALL CPP FILES
CPP_SRC += $(wildcard $(SRC_DIR)/rlImGui/*.cpp) #GET LIST OF ALL CPP FILES
ifeq ($(IMGUI_MODE), BUILD)
CPP_SRC += $(wildcard $(SRC_DIR)/imgui/*.cpp) #GET LIST OF ALL CPP FILES
EXTRA_DIRS += $(OBJ_DIR)/imgui
endif
ifeq ($(IMGUI_MODE), DYN_LIBRARY)
LDLIBS += -limgui
endif
#IF DYNAMIC MODE
ifeq ($(LIB_MODE), DYNAMIC)
LDLIBS += $(LD_DYNAMIC_LIBS)
endif
#IF STATIC MODE
ifeq ($(LIB_MODE), STATIC)
LDLIBS += $(LD_STATIC_LIBS)
CPPFLAGS += -I$(STATIC_INCLUDE_DIR)
endif
C_OBJ := $(patsubst $(SRC_DIR)/%.c, $(OBJ_DIR)/%.o, $(C_SRC)) #MAKE LIST OF ALL C OBJECT FILES THAT NEED TO BE BUILT
CPP_OBJ := $(patsubst $(SRC_DIR)/%.cpp, $(OBJ_DIR)/%.o, $(CPP_SRC)) #MAKE LIST OF ALL CPP OBJECT FILES THAT NEED TO BE BUILT
OBJ := $(C_OBJ) $(CPP_OBJ)
all: $(EXE)
$(EXE): $(OBJ) | $(BIN_DIR)
$(CXX) $(LDFLAGS) $^ $(LDLIBS) -o $@
$(OBJ_DIR)/%.o: $(SRC_DIR)/%.c | $(OBJ_DIR)
$(CC) $(CFLAGS) -c $< -o $@
$(OBJ_DIR)/%.o: $(SRC_DIR)/%.cpp | $(OBJ_DIR)
$(CXX) $(CPPFLAGS) $(CXXFLAGS) -c $< -o $@
$(BIN_DIR) $(OBJ_DIR): | $(EXTRA_DIRS)
mkdir -p $@
$(EXTRA_DIRS):
mkdir -p $@
clean:
@$(RM) -rv $(BIN_DIR) $(OBJ_DIR)
.PHONY: all clean

6
README.md Normal file
View file

@ -0,0 +1,6 @@
# MPRIS MiniPlayer
Little program to dispaly whatever media in an mpris compatible player is playing. Recommended to use with playerctl.
Makefile should take care of building, you need raylib, imgui, and libmagic installed with headers.
### :) vs (: vs :3 showdown

BIN
assets/null.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 344 B

0
include/PUT_HEADERS_HERE Normal file
View file

1708
include/raylib.h Normal file

File diff suppressed because it is too large Load diff

2941
include/raymath.h Normal file

File diff suppressed because it is too large Load diff

5262
include/rlgl.h Normal file

File diff suppressed because it is too large Load diff

0
lib/PUT_STATIC_LIBS_HERE Normal file
View file

287
src/main.cpp Normal file
View file

@ -0,0 +1,287 @@
/*******************************************************************************************
*
* raylib-extras [ImGui] example - Docking example
*
* This is an example of using the ImGui docking features that are part of docking branch
* You must replace the default imgui with the code from the docking branch for this to work
* https://github.com/ocornut/imgui/tree/docking
*
* Copyright (c) 2024 Jeffery Myers
*
********************************************************************************************/
#include "mpris_connection.hpp"
#include <exception>
#include <iterator>
#include <sdbus-c++/IConnection.h>
#include <sdbus-c++/IObject.h>
#include <sdbus-c++/IProxy.h>
#include <sdbus-c++/Types.h>
#define IMGUI_DEFINE_MATH_OPERATORS
#include "raylib.h"
#include "raymath.h"
#include <optional>
#include <unordered_map>
#include <vector>
#include "imgui.h"
#include "imgui_stdlib.h"
#include "rlImGui/rlImGui.h"
#include "testcpp.hpp"
#include "stdio.h"
#include <fstream>
#include <iostream>
#include <sdbus-c++/sdbus-c++.h>
#include <string>
extern "C" {
#include "testc.h"
}
class RayWindow {
public:
bool Open = false;
RenderTexture ViewTexture;
virtual void Setup() = 0;
virtual void Shutdown() = 0;
virtual void Show() = 0;
virtual void Update() = 0;
bool Focused = false;
Rectangle ContentRect = {0};
};
class RayWindowExample {
public:
RenderTexture ViewTexture;
bool Open = true;
bool Focused = false;
bool Resized = false;
ImVec2 PastSize;
RayWindowExample() {
ViewTexture = LoadRenderTexture(GetScreenWidth(), GetScreenWidth());
// ViewTexture = LoadRenderTexture(256, 256);
printf("window w,h: %d, %d \n", ViewTexture.texture.width, ViewTexture.texture.height);
PastSize = ImVec2{256, 256};
Resized = false;
}
~RayWindowExample() {
UnloadRenderTexture(ViewTexture);
}
void Show() {
ImGui::PushStyleVar(ImGuiStyleVar_WindowPadding, ImVec2(0, 0));
ImGui::SetNextWindowSize(ImVec2(256, 275), ImGuiCond_FirstUseEver);
if (ImGui::Begin("Raylib in ImGUI", &Open, ImGuiWindowFlags_NoScrollbar)) {
Focused = ImGui::IsWindowFocused(ImGuiFocusedFlags_ChildWindows);
ImVec2 DaZone = ImGui::GetContentRegionAvail();
rlImGuiImageRenderTexture(&ViewTexture);
// rlImGuiImage(&ViewTexture.texture);
if (PastSize != DaZone) {
Resized = true;
} else {
Resized = false;
}
PastSize = DaZone;
}
ImGui::End();
ImGui::PopStyleVar();
}
void Update() {
if (!Open) {
return;
}
if (Resized) {
UnloadRenderTexture(ViewTexture);
ViewTexture = LoadRenderTexture(PastSize.x, PastSize.y);
}
BeginTextureMode(ViewTexture);
ClearBackground(SKYBLUE);
DrawCircle(0, 0, 35, RED);
// DrawPixel(0,0, BLUE);
// DrawRectangleLines(0,0,PastSize.x,PastSize.y, RED);
Rectangle rec = Rectangle{0, 0, PastSize.x, PastSize.y};
// DrawRectangleLinesEx(rec, 2, RED);
EndTextureMode();
}
};
std::vector<std::string> GetMprisServices() {
auto connection = sdbus::createSessionBusConnection();
sdbus::ServiceName dest{"org.freedesktop.DBus"};
sdbus::ObjectPath objec{"/org/freedesktop/DBus"};
auto prox = sdbus::createProxy(dest, objec);
sdbus::InterfaceName interfaceName{"org.freedesktop.DBus"};
sdbus::MethodName introspect("ListNames");
auto method = prox->createMethodCall(interfaceName, introspect);
auto reply = prox->callMethod(method);
std::vector<std::string> res;
reply >> res;
std::vector<std::string> ret;
for (std::string item : res) {
if (item.find("org.mpris.MediaPlayer2") != std::string::npos) {
ret.push_back(item);
}
}
return ret;
}
int main(int argc, char *argv[]) {
// Initialization
//--------------------------------------------------------------------------------------
int screenWidth = 1280;
int screenHeight = 800;
// SetConfigFlags(FLAG_MSAA_4X_HINT | FLAG_WINDOW_RESIZABLE);
SetConfigFlags(FLAG_MSAA_4X_HINT | FLAG_VSYNC_HINT | FLAG_WINDOW_RESIZABLE);
InitWindow(screenWidth, screenHeight, "raylib-Extras [ImGui] example - Docking");
SetTargetFPS(120);
rlImGuiSetup(true);
ImGui::GetStyle().AntiAliasedLinesUseTex = false;
TestC();
TestCPPFunc();
bool run = true;
bool showDemoWindow = false;
std::vector<std::string> serviceList = GetMprisServices();
auto current_player = MprisPlayer("org.mpris.MediaPlayer2.playerctld");
// current_player.pp();
/*
auto connection = sdbus::createSessionBusConnection();
sdbus::ServiceName dest{"org.freedesktop.DBus"};
sdbus::ObjectPath objec{"/org/freedesktop/DBus"};
auto prox = sdbus::createProxy(dest, objec);
sdbus::InterfaceName interfaceName{"org.freedesktop.DBus"};
sdbus::MethodName introspect("ListNames");
auto method = prox->createMethodCall(interfaceName, introspect);
auto reply = prox->callMethod(method);
std::vector<std::string> res;
reply >> res;
for (std::string item : res) {
std::cout << item << std::endl;
}
*/
// if the linked ImGui has docking, enable it.
// this will only be true if you use the docking branch of ImGui.
#ifdef IMGUI_HAS_DOCK
ImGui::GetIO().ConfigFlags |= ImGuiConfigFlags_DockingEnable;
#endif
// for (json::iterator it = course_info.begin(); it != course_info.end(); ++it) {
// std::cout << *it << std::endl;
// }
// Main game loop
while (!WindowShouldClose() &&
run) // Detect window close button or ESC key, or a quit from the menu
{
BeginDrawing();
ClearBackground(DARKGRAY);
// start ImGui content
rlImGuiBegin();
// if you want windows to dock to the viewport, call this.
#ifdef IMGUI_HAS_DOCK
ImGui::DockSpaceOverViewport();
#endif
// show a simple menu bar
if (ImGui::BeginMainMenuBar()) {
if (ImGui::BeginMenu("File")) {
#ifdef IMGUI_HAS_DOCK
if (ImGui::MenuItem("Enable Docking")) {
ImGui::GetIO().ConfigFlags |= ImGuiConfigFlags_DockingEnable;
}
if (ImGui::MenuItem("Disable Docking")) {
ImGui::GetIO().ConfigFlags &= ~ImGuiConfigFlags_DockingEnable;
}
#endif
if (ImGui::MenuItem("Quit"))
run = false;
ImGui::EndMenu();
}
if (ImGui::BeginMenu("Players")) {
for (auto item : serviceList) {
if (ImGui::MenuItem(item.c_str())) {
current_player = MprisPlayer(item);
}
}
ImGui::EndMenu();
}
if (ImGui::BeginMenu("Window")) {
if (ImGui::MenuItem("Demo Window", nullptr, showDemoWindow))
showDemoWindow = !showDemoWindow;
ImGui::EndMenu();
}
ImGui::EndMainMenuBar();
}
// show some windows
if (ImGui::Begin("Player Control")) {
ImGui::Text("%s", current_player.GetIdentity().c_str());
ImGui::Text(
"%s",
current_player.GetCurrentMetadata()["mpris:artUrl"].get<std::string>().c_str());
if (ImGui::Button("Prev")) {
current_player.Prev();
}
if (ImGui::Button("Play/Pause")) {
current_player.PausePlay();
}
if (ImGui::Button("Next")) {
current_player.Next();
}
if (ImGui::Button("Refresh")) {
current_player.Refresh();
current_player.UpdateTexture();
}
//rlImGuiImage(&current_player.tex.tex);
rlImGuiImageSize(&current_player.tex.tex,300,300);
}
ImGui::End();
if (showDemoWindow)
ImGui::ShowDemoWindow(&showDemoWindow);
// end ImGui Content
rlImGuiEnd();
EndDrawing();
//----------------------------------------------------------------------------------
}
rlImGuiShutdown();
// De-Initialization
//--------------------------------------------------------------------------------------
CloseWindow(); // Close window and OpenGL context
//--------------------------------------------------------------------------------------
return 0;
}

153
src/mpris_connection.cpp Normal file
View file

@ -0,0 +1,153 @@
#include "mpris_connection.hpp"
#include <sdbus-c++/IConnection.h>
#include <sdbus-c++/Types.h>
#include <string>
#define IMGUI_DEFINE_MATH_OPERATORS
#include "imgui.h"
#include <iostream>
#include <ostream>
#include <magic.h>
#include <unordered_map>
MprisPlayer::MprisPlayer(std::string servicename) {
bus_connection = sdbus::createSessionBusConnection();
sdbus::ServiceName dest{servicename};
sdbus::ObjectPath objec{"/org/mpris/MediaPlayer2"};
PlayerProxy = sdbus::createProxy(dest, objec);
mp2 = "org.mpris.MediaPlayer2.Player";
playpause = "PlayPause";
Refresh();
}
void MprisPlayer::PausePlay() {
auto method = PlayerProxy->createMethodCall(mp2, playpause);
auto reply = PlayerProxy->callMethod(method);
}
void MprisPlayer::Next() {
auto method = PlayerProxy->createMethodCall(mp2, sdbus::MethodName("Next"));
try {
auto reply = PlayerProxy->callMethod(method);
} catch (const std::exception &e) {}
}
void MprisPlayer::Prev() {
auto method = PlayerProxy->createMethodCall(mp2, sdbus::MethodName("Previous"));
auto reply = PlayerProxy->callMethod(method);
}
std::string MprisPlayer::GetIdentity() {
return identity;
}
std::unordered_map<std::string, sdbus::Variant> MprisPlayer::GetCurrentMetadata() {
return current_metadata;
}
void MprisPlayer::Refresh() {
identity = PlayerProxy->getProperty("Identity")
.onInterface("org.mpris.MediaPlayer2")
.get<std::string>();
current_metadata = PlayerProxy->getProperty("Metadata")
.onInterface("org.mpris.MediaPlayer2.Player")
.get<std::unordered_map<std::string, sdbus::Variant>>();
return;
}
void MprisPlayer::UpdateTexture() {
auto metadata = GetCurrentMetadata();
std::string filename = metadata["mpris:artUrl"].get<std::string>();
if (filename.length() > 0) {
if (filename.c_str()[0] == 'f') {
std::cout << "parsing as file" << std::endl;
std::cout << filename << std::endl;
std::string path = filename.substr(7);
FILE * f = fopen(path.c_str(), "r");
if (f == NULL) {
tex = RayTexture();
fclose(f);
return;
}
fseek(f, 0, SEEK_END);
long size = ftell(f);
rewind(f);
unsigned char* buffer = new unsigned char[size];
fread(buffer, size, 1, f);
magic_t magic = magic_open(MAGIC_MIME_TYPE);
if (magic == NULL) {
tex = RayTexture();
delete[] buffer;
fclose(f);
return;
}
if (magic_load(magic, NULL) != 0) {
tex = RayTexture();
delete[] buffer;
fclose(f);
return;
}
const char *mime_type = magic_file(magic, path.c_str());
if (mime_type == NULL) {
tex = RayTexture();
delete[] buffer;
fclose(f);
return;
}
std::cout << mime_type << std::endl;
if (strcmp(mime_type, "image/png") == 0 ) {
auto img = LoadImageFromMemory(".png", buffer, size);
tex = RayTexture(img);
UnloadImage(img);
} else if (strcmp(mime_type, "image/jpeg") == 0 ) {
auto img = LoadImageFromMemory(".jpg", buffer, size);
tex = RayTexture(img);
UnloadImage(img);
} else {
tex = RayTexture();
}
delete[] buffer;
fclose(f);
return;
}
}
}
RayTexture::RayTexture() {
tex = LoadTexture(ASSET_DIR "/null.png" );
path = ASSET_DIR "/null.png";
}
RayTexture::RayTexture(Image img) {
path = "NOPATH";
tex = LoadTextureFromImage(img);
}
RayTexture::RayTexture(const RayTexture &other) {
path = other.path;
auto img = LoadImageFromTexture(other.tex);
tex = LoadTextureFromImage(img);
UnloadImage(img);
}
RayTexture &RayTexture::operator=(const RayTexture &other) {
if (this == &other) {
return *this;
}
printf("HERE\n");
RayTexture temp(other);
std::swap(tex, temp.tex);
std::swap(path, temp.path);
return *this;
}
RayTexture::~RayTexture() {
if (IsWindowReady()) {
UnloadTexture(tex);
}
}

45
src/mpris_connection.hpp Normal file
View file

@ -0,0 +1,45 @@
#ifndef COURSE_H
#define COURSE_H
#include <sdbus-c++/Types.h>
#include <unordered_map>
#define IMGUI_DEFINE_MATH_OPERATORS
#include <imgui.h>
#include <memory>
#include <raylib.h>
#include <sdbus-c++/IConnection.h>
#include <sdbus-c++/IProxy.h>
#include <string>
class RayTexture {
public:
Texture tex{};
std::string path;
RayTexture();
explicit RayTexture(Image img);
RayTexture(const RayTexture& other);
RayTexture& operator=(const RayTexture& other);
~RayTexture();
};
class MprisPlayer {
public:
std::unique_ptr<sdbus::IConnection> bus_connection;
std::unique_ptr<sdbus::IProxy> PlayerProxy;
sdbus::InterfaceName mp2;
sdbus::MethodName playpause;
RayTexture tex;
explicit MprisPlayer(std::string servicename);
void PausePlay();
void Refresh();
void UpdateTexture();
void Next();
void Prev();
std::string identity;
std::string GetIdentity();
std::unordered_map<std::string, sdbus::Variant> current_metadata;
std::unordered_map<std::string, sdbus::Variant> GetCurrentMetadata();
};
#endif

16
src/rlImGui/LICENSE Normal file
View file

@ -0,0 +1,16 @@
Copyright (c) 2020-2021 Jeffery Myers
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.

75
src/rlImGui/README.md Normal file
View file

@ -0,0 +1,75 @@
# rlImGui
<img align="left" src="https://github.com/raysan5/raylib/raw/master/logo/raylib_logo_animation.gif" width="64">
A Raylib integration with DearImGui
rlImgui provides a backend for [Dear ImGui](https://github.com/ocornut/imgui) using [Raylib](https://www.raylib.com/).
# Building
rlImGui is setup to use premake to generate a static library and examples for Visual Studio 2019. Premake can also be used to generate makefiles for linux. rlImGui can be used as a static library, or by direclty including the files into your game project.
If you wish to use premake, you will need to download the Premake5 executable for your platform from. https://premake.github.io/download
# Setup
Using rlImGui in your code is very easy. Once you have included the library, or source files for rlImGui and ImGui in your project, simply do the following.
```
#include "rlImGui.h" // include the API header
// before your game loop
rlImGuiSetup(true); // sets up ImGui with ether a dark or light default theme
// inside your game loop, between BeginDrawing() and EndDrawing()
rlImGuiBegin(); // starts the ImGui content mode. Make all ImGui calls after this
rlImGuiEnd(); // ends the ImGui content mode. Make all ImGui calls before this
// after your game loop is over, before you close the window
rlImGuiShutdown(); // cleans up ImGui
```
# Examples
There are two example programs in the examples folder.
## Simple
This is the most simple use of ImGui in raylib, it just shows the ImGui demo window.
![image](https://user-images.githubusercontent.com/322174/136596910-da1b60ae-4a39-48f0-ae84-f568bc396870.png)
## Editor
This is a more complex example of ImGui, showing how to use raylib 2d and 3d cameras to draw into ImGui windows using render textures.
![image](https://user-images.githubusercontent.com/322174/136596949-033ffe0a-2476-4030-988a-5bf5b6e2ade7.png)
# Extras
## rlImGuiColors.h
This file has a converter to change Raylib colors into ImGui Colors
## Font Awesome Icons
Support for Font Awesome 6 https://fontawesome.com/ is built into rlImGui and enabled by default. You can simply
#include "extras/IconsFontAwesome6.h"
To use the ICON_FA macros for any icon in the free set.
If you wish to disable font awesome support you can #define NO_FONT_AWESOME
# Images
Raylib textures can be drawn in ImGui using the following functions
```
void rlImGuiImage(const Texture *image);
void rlImGuiImageSize(const Texture *image, int width, int height);
void rlImGuiImageSizeV(const Texture* image, Vector2 size);
void rlImGuiImageRect(const Texture* image, int destWidth, int destHeight, Rectangle sourceRect);
void rlImGuiImageRenderTexture(const RenderTexture* image);
void rlImGuiImageRenderTextureFit(const RenderTexture* image, bool center);
bool rlImGuiImageButton(const Texture *image);
bool rlImGuiImageButtonSize(const char* name, const Texture* image, struct ImVec2 size);
```
# C vs C++
ImGui is a C++ library, so rlImGui uses C++ to create the backend and integration with Raylib.
The rlImGui.h API only uses features that are common to C and C++, so rlImGui can be built as a static library and used by pure C code. Users of ImGui who wish to use pure C must use an ImGui wrapper, such as [https://github.com/cimgui/cimgui].
# Low level API
If you would like more controll over the ImGui Backend, you can use the low level API that is found in imgui_impl_raylib.h. This is API follows the patterns of other ImGui backends and does not do automatic context management. An example of it's use can be found in imgui_style_example.cpp

View file

@ -0,0 +1,280 @@
/*******************************************************************************************
*
* raylib-extras [ImGui] example - asset browser
*
* This is a more complex ImGui Integration
* It shows how to build windows on top of 2d and 3d views using a render texture
*
* Copyright (c) 2024 Jeffery Myers
*
********************************************************************************************/
#define _CRT_NONSTDC_NO_WARNINGS
#include "asset_browser.h"
#include "imgui_utils.h"
#include "imgui.h"
#include "imgui_internal.h"
#include "raylib.h"
#include "extras/IconsFontAwesome6.h"
#include <algorithm>
AssetBrowserPanel::AssetBrowserPanel()
{
AssetRoot = GetWorkingDirectory();
RebuildFolderTree();
SetCurrentFolder(&FolderRoot);
CurrentView = &ListView;
}
void AssetBrowserPanel::Show()
{
ShowHeader();
ImGuiTableFlags flags = ImGuiTableFlags_Resizable | ImGuiTableFlags_SizingStretchSame | ImGuiTableFlags_Borders;
if (ImGui::BeginTable("AssetBrowserTab", 2, flags, ImGui::GetContentRegionAvail()))
{
ImGui::TableSetupColumn("FolderView", ImGuiTableColumnFlags_None, 0.25f);
ImGui::TableSetupColumn("AssetView", ImGuiTableColumnFlags_None, 0.75f);
ImGui::TableNextRow();
ImGui::TableNextColumn();
if (ImGui::BeginChild("FolderList", ImGui::GetContentRegionAvail(),ImGuiChildFlags_None, ImGuiWindowFlags_None))
{
ShowFolderTree();
ImGui::EndChild();
}
ImGui::TableNextColumn();
ShowFilePane();
ImGui::EndTable();
}
}
void AssetBrowserPanel::RebuildFolderTree()
{
FolderRoot.Children.clear();
FolderRoot.FullPath = AssetRoot;
FolderRoot.Name = GetFileNameWithoutExt(AssetRoot.c_str());
FolderRoot.Parent = nullptr;
FolderRoot.Icon = ICON_FA_SERVER;
FolderRoot.ForceOpenNextFrame = true;
FolderRoot.PopulateChildren();
}
void AssetBrowserPanel::SetCurrentFolder(FolderInfo* folder)
{
if (CurrentFolderContents.Folder == folder)
return;
CurrentFolderContents.Folder = folder;
CurrentFolderContents.Files.clear();
if (folder == nullptr)
return;
FolderInfo* openFolder = folder;
while (openFolder != nullptr)
{
openFolder->ForceOpenNextFrame = true;
openFolder = openFolder->Parent;
}
auto files = LoadDirectoryFiles(CurrentFolderContents.Folder->FullPath.c_str());
for (unsigned int i = 0; i < files.count; i++)
{
if (DirectoryExists(files.paths[i]))
continue;
const char* name = GetFileName(files.paths[i]);
if (!name || *name == '.')
continue;
FileInfo& file = CurrentFolderContents.Files.emplace_back();
file.FullPath = files.paths[i];
file.Name = name;
file.Icon = GetFileIcon(name);
}
UnloadDirectoryFiles(files);
}
void AssetBrowserPanel::FolderInfo::PopulateChildren()
{
constexpr Color folderColor = { 255,255,145,255 };
auto folders = LoadDirectoryFiles(FullPath.c_str());
for (unsigned int i = 0; i < folders.count; i++)
{
if (DirectoryExists(folders.paths[i]))
{
const char* name = GetFileNameWithoutExt(folders.paths[i]);
if (!name || *name == '.')
continue;
FolderInfo& child = Children.emplace_back();
child.FullPath = folders.paths[i];
child.Name = name;
child.Parent = this;
child.Tint = folderColor;
child.Icon = ICON_FA_FOLDER;
child.PopulateChildren();
}
}
UnloadDirectoryFiles(folders);
}
bool AssetBrowserPanel::ShowFolderTreeNode(FolderInfo& info)
{
ImGuiTreeNodeFlags flags = ImGuiTreeNodeFlags_OpenOnArrow | ImGuiTreeNodeFlags_OpenOnDoubleClick;
if (info.Children.empty())
flags |= ImGuiTreeNodeFlags_Leaf;
if (CurrentFolderContents.Folder == &info)
flags |= ImGuiTreeNodeFlags_Selected;
if (info.ForceOpenNextFrame)
{
ImGui::SetNextItemOpen(true);
}
bool open = ImGui::TreeNodeEx(info.Name.c_str(), flags, "%s %s", info.Icon.c_str(), info.Name.c_str());
if (info.ForceOpenNextFrame && CurrentFolderContents.Folder == &info)
ImGui::ScrollToItem(ImGuiScrollFlags_KeepVisibleCenterY);
info.ForceOpenNextFrame = false;
if (ImGui::IsItemClicked())
SetCurrentFolder(&info);
if (open)
{
for (auto& node : info.Children)
ShowFolderTreeNode(node);
ImGui::TreePop();
}
return CurrentFolderContents.Folder == &info;
}
void AssetBrowserPanel::ShowHeader()
{
ImGui::PushStyleVar(ImGuiStyleVar_ChildBorderSize, 1);
if (ImGui::BeginChild("Header", ImVec2{ ImGui::GetContentRegionAvail().x, ImGui::GetFrameHeight() }))
{
ImGui::Text("%s Root", ICON_FA_FOLDER_OPEN);
ImGui::SameLine();
ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x * 0.33f);
ImGui::InputText("###Path", (char*)(CurrentFolderContents.Folder->FullPath.c_str() + AssetRoot.size()), CurrentFolderContents.Folder->FullPath.size(), ImGuiInputTextFlags_ReadOnly);
ImGui::EndChild();
}
ImGui::PopStyleVar();
}
void AssetBrowserPanel::ShowFolderTree()
{
ShowFolderTreeNode(FolderRoot);
}
void AssetBrowserPanel::ShowFilePane()
{
if (ImGui::BeginChild("FileList", ImGui::GetContentRegionAvail(), ImGuiChildFlags_None, ImGuiWindowFlags_None))
{
if (CurrentView)
{
auto *item = CurrentView->Show(CurrentFolderContents);
if (item)
{
AssetItemInfo* assetItem = static_cast<AssetItemInfo*>(item);
if (!assetItem->IsFile())
SetCurrentFolder(static_cast<FolderInfo*>(item));
}
}
ImGui::EndChild();
}
}
ViewableItem* AssetBrowserPanel::AssetContainer::Reset()
{
FileItr = Files.begin();
FolderItr = Folder->Children.begin();
if (FileItr != Files.end())
return &(*FileItr);
if (FolderItr != Folder->Children.end())
return &(*FolderItr);
return nullptr;
}
size_t AssetBrowserPanel::AssetContainer::Count()
{
return Files.size() + Folder->Children.size();
}
ViewableItem* AssetBrowserPanel::AssetContainer::Next()
{
if (FileItr != Files.end())
{
FileItr++;
if (FileItr != Files.end())
return &(*FileItr);
else
{
if (FolderItr != Folder->Children.end())
return &(*FolderItr);
else
return nullptr;
}
}
if (FolderItr != Folder->Children.end())
{
FolderItr++;
if (FolderItr != Folder->Children.end())
return &(*FolderItr);
}
return nullptr;
}
const char* AssetBrowserPanel::GetFileIcon(const char* filename)
{
const char* e = GetFileExtension(filename);
if (e == nullptr)
return ICON_FA_FILE;
std::string ext = e;
std::transform(ext.begin(), ext.end(), ext.begin(),
[](unsigned char c) { return std::tolower(c); } // correct
);
if (!ext.empty())
{
if (ext==".png")
return ICON_FA_FILE_IMAGE;
if (ext==".wav" || ext==".mp3" || ext==".oog")
return ICON_FA_FILE_AUDIO;
if (ext==".ttf" || ext==".otf" || ext==".fnt")
return ICON_FA_FONT;
if (ext==".txt" || ext==".md")
return ICON_FA_FILE_LINES;
if (ext==".lua" || ext==".c" || ext==".h" || ext==".cpp")
return ICON_FA_FILE_CODE;
}
return ICON_FA_FILE;
}

View file

@ -0,0 +1,95 @@
/*******************************************************************************************
*
* raylib-extras [ImGui] example - asset browser
*
* This is a more complex ImGui Integration
* It shows how to build windows on top of 2d and 3d views using a render texture
*
* Copyright (c) 2024 Jeffery Myers
*
********************************************************************************************/
#pragma once
#include "item_view.h"
#include "raylib.h"
#include <string>
#include <vector>
#include <list>
class AssetBrowserPanel
{
public:
AssetBrowserPanel();
void Show();
private:
std::string AssetRoot;
class AssetItemInfo : public ViewableItem
{
protected:
bool File = false;
public:
AssetItemInfo(bool file) : File(file) {}
bool IsFile() const { return File; }
};
class FileInfo : public AssetItemInfo
{
public:
FileInfo() : AssetItemInfo(true) {}
std::string FullPath;
};
class FolderInfo : public AssetItemInfo
{
public:
FolderInfo() : AssetItemInfo(false) {}
std::string FullPath;
FolderInfo* Parent = nullptr;
std::list<FolderInfo> Children;
bool ForceOpenNextFrame = false;
void PopulateChildren();
};
FolderInfo FolderRoot;
class AssetContainer : public ViewableItemContainer
{
public:
ViewableItem* Reset() override;
size_t Count() override;
ViewableItem* Next() override;
FolderInfo* Folder = nullptr;
std::vector<FileInfo> Files;
std::vector<FileInfo>::iterator FileItr;
std::list<FolderInfo>::iterator FolderItr;
};
AssetContainer CurrentFolderContents;
ListItemView ListView;
ItemView* CurrentView = nullptr;
void RebuildFolderTree();
void SetCurrentFolder(FolderInfo* folder);
bool ShowFolderTreeNode(FolderInfo& folder);
void ShowFolderTree();
void ShowFilePane();
void ShowHeader();
const char* GetFileIcon(const char* filename);
};

View file

@ -0,0 +1,94 @@
/*******************************************************************************************
*
* raylib-extras [ImGui] example - asset browser
*
* This is a more complex ImGui Integration
* It shows how to build windows on top of 2d and 3d views using a render texture
*
* Copyright (c) 2024 Jeffery Myers
*
********************************************************************************************/
#include "imgui_utils.h"
#include "imgui.h"
#include "imgui_internal.h"
namespace ImGuiUtils
{
bool IsSpace(char aCharacter)
{
// all space characters are values 32 or less (space is 32)
// so we can convert them to a bitmask and use a single condition
const int mask = (1 << (' ' - 1)) | (1 << ('\f' - 1)) | (1 << ('\n' - 1)) | (1 << ('\r' - 1)) | (1 << ('\t' - 1)) | (1 << ('\v' - 1));
return (mask & (1 << ((aCharacter && aCharacter <= 32) * (aCharacter - 1)))) != 0;
}
//-------------------------------------------------------------------------------------------------
// Todo: Add support for soft-hyphens when using word boundaries?
//-------------------------------------------------------------------------------------------------
void TextWithEllipsis(const char* string, float aMaxWidth, bool useWordBoundaries, float aSpacing)
{
char const* partStart = string;
char const* partEnd = string;
ImWchar elipsisChar = ImGui::GetFont()->EllipsisChar;
char elipsisText[8];
ImTextStrToUtf8(elipsisText, sizeof(elipsisText), &elipsisChar, (&elipsisChar) + 1);
if (aSpacing < 0.0f) aSpacing = ImGui::GetStyle().ItemSpacing.x;
float const ellipsisWidth = ImGui::CalcTextSize(elipsisText).x + aSpacing;
float width = 0;
bool addElipsis = false;
while (*partStart != 0 )
{
// Add space to next segment
while (IsSpace(*partEnd))
partEnd++;
if (useWordBoundaries)
{
// get next 'word' by looking for space after non-space
while (*partEnd != 0 && !IsSpace(*partEnd))
++partEnd;
}
else
{
if (*partEnd != 0)
++partEnd;
}
ImVec2 const wordSize = ImGui::CalcTextSize(partStart, partEnd);
// Clearly we have space for this word so just add it
if (wordSize.x + width + ellipsisWidth < aMaxWidth)
{
width += wordSize.x;
partStart = partEnd;
}
// If we're just at the end of the word and we just fit then we can commit here
else if (*partEnd == 0 && wordSize.x + width < aMaxWidth)
{
width += wordSize.x;
partStart = partEnd;
}
// we're done so add elipsis where the current segment starts
else
{
addElipsis = true;
break;
}
}
ImGui::TextUnformatted(string, partStart);
if (addElipsis)
{
ImGui::SameLine(0.0f, aSpacing);
ImGui::TextUnformatted(elipsisText);
}
}
}

View file

@ -0,0 +1,19 @@
/*******************************************************************************************
*
* raylib-extras [ImGui] example - asset browser
*
* This is a more complex ImGui Integration
* It shows how to build windows on top of 2d and 3d views using a render texture
*
* Copyright (c) 2024 Jeffery Myers
*
********************************************************************************************/
#pragma once
#include <string>
namespace ImGuiUtils
{
void TextWithEllipsis(const char* string, float maxWidth, bool useWordBoundaries = false, float aSpacing = 0);
}

View file

@ -0,0 +1,47 @@
/*******************************************************************************************
*
* raylib-extras [ImGui] example - asset browser
*
* This is a more complex ImGui Integration
* It shows how to build windows on top of 2d and 3d views using a render texture
*
* Copyright (c) 2024 Jeffery Myers
*
********************************************************************************************/
#pragma once
#include <string>
#include "raylib.h"
class ViewableItem
{
public:
virtual ~ViewableItem() = default;
std::string Name;
std::string Icon;
Color Tint = BLANK;
};
class ViewableItemContainer
{
public:
virtual ~ViewableItemContainer() = default;
virtual ViewableItem* Reset() = 0;
virtual size_t Count() = 0;
virtual ViewableItem* Next() = 0;
};
class ItemView
{
public:
virtual ~ItemView() = default;
virtual ViewableItem* Show(ViewableItemContainer& container) = 0;
};
class ListItemView : public ItemView
{
public:
ViewableItem* Show(ViewableItemContainer& container) override;
};

View file

@ -0,0 +1,53 @@
/*******************************************************************************************
*
* raylib-extras [ImGui] example - asset browser
*
* This is a more complex ImGui Integration
* It shows how to build windows on top of 2d and 3d views using a render texture
*
* Copyright (c) 2024 Jeffery Myers
*
********************************************************************************************/
#include "item_view.h"
#include "imgui.h"
#include "imgui_utils.h"
#include "rlImGuiColors.h"
#include "raylib.h"
extern ImFont* IconFont;
ViewableItem* ListItemView::Show(ViewableItemContainer& container)
{
ViewableItem* item = container.Reset();
ViewableItem* selected = nullptr;
while (item)
{
float x = ImGui::GetCursorPosX();
const char* name = TextFormat("###%s", item->Name.c_str());
if (item->Tint.a > 0)
ImGui::TextColored(rlImGuiColors::Convert(item->Tint), " %s", item->Icon.c_str());
else
ImGui::Text(" %s", item->Icon.c_str());
ImGui::SameLine(0, 0);
ImGui::Text(" %s", item->Name.c_str());
ImGui::SameLine(0, 0);
ImGui::SetCursorPosX(x);
//ImGui::SetItemAllowOverlap();
ImGui::Selectable(name);
if (ImGui::IsItemHovered() && ImGui::IsMouseDoubleClicked(0))
{
selected = item;
}
item = container.Next();
}
return selected;
}

View file

@ -0,0 +1,96 @@
/*******************************************************************************************
*
* raylib-extras [ImGui] example - asset browser
*
* This is a more complex ImGui Integration
* It shows how to build windows on top of 2d and 3d views using a render texture
*
* Copyright (c) 2024 Jeffery Myers
*
********************************************************************************************/
#include "raylib.h"
#include "raymath.h"
#include "imgui.h"
#include "rlImGui.h"
#include "rlImGuiColors.h"
#include "extras/FA6FreeSolidFontData.h"
#include "asset_browser.h"
#include <limits>
ImFont* IconFont = nullptr;
int main(int argc, char* argv[])
{
// Initialization
//--------------------------------------------------------------------------------------
int screenWidth = 1900;
int screenHeight = 900;
SetConfigFlags(FLAG_MSAA_4X_HINT | FLAG_VSYNC_HINT);
InitWindow(screenWidth, screenHeight, "raylib-Extras [ImGui] example - Asset browser");
SetTargetFPS(144);
rlImGuiBeginInitImGui();
ImGui::StyleColorsDark();
static const ImWchar icons_ranges[] = { ICON_MIN_FA, ICON_MAX_FA, 0 };
ImFontConfig icons_config;
icons_config.MergeMode = true;
icons_config.PixelSnapH = true;
icons_config.FontDataOwnedByAtlas = false;
icons_config.GlyphMaxAdvanceX = std::numeric_limits<float>::max();
icons_config.RasterizerMultiply = 1.0f;
icons_config.OversampleH = 2;
icons_config.OversampleV = 1;
icons_config.GlyphRanges = icons_ranges;
ImGuiIO& io = ImGui::GetIO();
io.Fonts->AddFontFromMemoryCompressedTTF((void*)fa_solid_900_compressed_data, fa_solid_900_compressed_size, 12, &icons_config, icons_ranges);
icons_config.MergeMode = false;
IconFont = io.Fonts->AddFontFromMemoryCompressedTTF((void*)fa_solid_900_compressed_data, fa_solid_900_compressed_size, 72, &icons_config, icons_ranges);
rlImGuiEndInitImGui();
AssetBrowserPanel assetBrowser;
// Main game loop
while (!WindowShouldClose()) // Detect window close button or ESC key
{
BeginDrawing();
ClearBackground(DARKGRAY);
rlImGuiBegin();
ImGui::SetNextWindowPos(ImVec2(0, 0));
ImGui::SetNextWindowSize(ImVec2(float(GetScreenWidth()), float(GetScreenHeight())));
if (ImGui::Begin("Frame", 0, ImGuiWindowFlags_NoDecoration | ImGuiWindowFlags_NoSavedSettings))
{
assetBrowser.Show();
}
ImGui::End();
rlImGuiEnd();
EndDrawing();
//----------------------------------------------------------------------------------
}
rlImGuiShutdown();
// De-Initialization
//--------------------------------------------------------------------------------------
CloseWindow(); // Close window and OpenGL context
//--------------------------------------------------------------------------------------
return 0;
}

Some files were not shown because too many files have changed in this diff Show more