Refactor lib view
This commit is contained in:
parent
5106cc3b71
commit
36efa46848
9 changed files with 270 additions and 427 deletions
|
|
@ -2,7 +2,7 @@ project(LibraryViewer)
|
||||||
|
|
||||||
### ---------------------- Externals --------------------- ###
|
### ---------------------- Externals --------------------- ###
|
||||||
set(BINDINGS_INCLUDE ../Externals/glfw/include ${GLEW_INCLUDE_DIR} ${PORTAUDIO_INCLUDE_DIR})
|
set(BINDINGS_INCLUDE ../Externals/glfw/include ${GLEW_INCLUDE_DIR} ${PORTAUDIO_INCLUDE_DIR})
|
||||||
set(BINDINGS_LIBS glfw ${GLEW_LIB} ${ALSA_LIBRARY} ${PORTAUDIO_LIB})
|
set(BINDINGS_LIBS glfw Imgui ${GLEW_LIB} ${ALSA_LIBRARY} ${PORTAUDIO_LIB})
|
||||||
|
|
||||||
### ---------------------- Static Library --------------------- ###
|
### ---------------------- Static Library --------------------- ###
|
||||||
file(GLOB SOURCES "./private/*.cpp" "./private/*/*.cpp")
|
file(GLOB SOURCES "./private/*.cpp" "./private/*/*.cpp")
|
||||||
|
|
@ -14,7 +14,7 @@ target_include_directories(${PROJECT_NAME} PUBLIC ./public/ ${BINDINGS_INCLUDE}
|
||||||
target_link_libraries(${PROJECT_NAME} PUBLIC Graphics Connection Widgets)
|
target_link_libraries(${PROJECT_NAME} PUBLIC Graphics Connection Widgets)
|
||||||
target_link_libraries(${PROJECT_NAME} PUBLIC ${BINDINGS_LIBS})
|
target_link_libraries(${PROJECT_NAME} PUBLIC ${BINDINGS_LIBS})
|
||||||
|
|
||||||
file(COPY "library" DESTINATION "${CMAKE_BINARY_DIR}/${PROJECT_NAME}/")
|
file(COPY "library" DESTINATION "${CMAKE_BINARY_DIR}/${PROJECT_NAME}")
|
||||||
file(COPY "applications/Font.ttf" DESTINATION "${CMAKE_BINARY_DIR}/${PROJECT_NAME}/")
|
file(COPY "applications/Font.ttf" DESTINATION "${CMAKE_BINARY_DIR}/${PROJECT_NAME}/")
|
||||||
|
|
||||||
### -------------------------- Applications -------------------------- ###
|
### -------------------------- Applications -------------------------- ###
|
||||||
|
|
|
||||||
|
|
@ -3,22 +3,27 @@
|
||||||
#include "Player.hpp"
|
#include "Player.hpp"
|
||||||
|
|
||||||
// 1) artworks
|
// 1) artworks
|
||||||
// 2) how to easy add more songs?
|
// 2) how to easily add more songs?
|
||||||
// 3) GUi :
|
// 3) GUi :
|
||||||
// - seeker
|
// - seeker
|
||||||
// - song idx
|
// - song idx
|
||||||
// - non existing highlight
|
// - non-existing highlight
|
||||||
// - prev next
|
// - prev next
|
||||||
// - remove debug gui
|
// - remove debug gui
|
||||||
// 4) queue & repeat & shuffle...
|
// 4) queue & repeat & shuffle...
|
||||||
// 5) new database with history
|
// 5) new database with history
|
||||||
|
|
||||||
void runApp() {
|
void runApp() {
|
||||||
|
|
||||||
Player player;
|
Player player;
|
||||||
Library library;
|
Library library;
|
||||||
library.loadJson(getHome() + "Library.json");
|
library.loadJson(getHome() + "Library.json");
|
||||||
library.checkExisting();
|
library.checkExisting();
|
||||||
LibraryWidget<tp::Window::Events, tp::Graphics::Canvas> gui(&library, &player);
|
|
||||||
|
tp::GlobalGUIConfig config;
|
||||||
|
tp::gGlobalGUIConfig = &config;
|
||||||
|
|
||||||
|
tp::LibraryWidget<tp::Window::Events, tp::Graphics::Canvas> gui(&library, &player);
|
||||||
|
|
||||||
auto window = tp::Window::createWindow(800, 600, "Window 1");
|
auto window = tp::Window::createWindow(800, 600, "Window 1");
|
||||||
|
|
||||||
|
|
@ -29,7 +34,7 @@ void runApp() {
|
||||||
auto area = window->getCanvas().getAvaliableArea();
|
auto area = window->getCanvas().getAvaliableArea();
|
||||||
|
|
||||||
gui.proc(window->getEvents(), {}, { area.x, area.y, area.z, area.w });
|
gui.proc(window->getEvents(), {}, { area.x, area.y, area.z, area.w });
|
||||||
gui.draw(window->getCanvas(), {}, { area.x, area.y, area.z, area.w });
|
gui.draw(window->getCanvas());
|
||||||
|
|
||||||
// tp::sleep(100);
|
// tp::sleep(100);
|
||||||
|
|
||||||
|
|
|
||||||
Binary file not shown.
BIN
LibraryViewer/library/tracks/2439.flac
Normal file
BIN
LibraryViewer/library/tracks/2439.flac
Normal file
Binary file not shown.
BIN
LibraryViewer/library/tracks/6477.flac
Normal file
BIN
LibraryViewer/library/tracks/6477.flac
Normal file
Binary file not shown.
BIN
LibraryViewer/library/tracks/6479.flac
Normal file
BIN
LibraryViewer/library/tracks/6479.flac
Normal file
Binary file not shown.
|
|
@ -1,12 +1,13 @@
|
||||||
|
|
||||||
#include "Library.hpp"
|
#include "Library.hpp"
|
||||||
#include "LocalConnection.hpp"
|
#include "LocalConnection.hpp"
|
||||||
|
#include "WidgetBase.hpp"
|
||||||
|
|
||||||
#include "picojson.h"
|
#include "picojson.h"
|
||||||
#include <filesystem>
|
#include <filesystem>
|
||||||
|
|
||||||
namespace tp {
|
namespace tp {
|
||||||
static ModuleManifest* deps[] = { &gModuleGraphics, &gModuleConnection, nullptr };
|
static ModuleManifest* deps[] = { &gModuleGraphics, &gModuleConnection, &gModuleWidgets, nullptr };
|
||||||
ModuleManifest gModuleLibraryViewer = ModuleManifest("LibraryViewer", nullptr, nullptr, deps);
|
ModuleManifest gModuleLibraryViewer = ModuleManifest("LibraryViewer", nullptr, nullptr, deps);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -25,13 +26,11 @@ tp::String getHome() {
|
||||||
out = (int1*) (std::string(envVarValue) + "/").c_str();
|
out = (int1*) (std::string(envVarValue) + "/").c_str();
|
||||||
return out;
|
return out;
|
||||||
} else {
|
} else {
|
||||||
return "";
|
return "library/";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
tp::String getSongLocalPath(SongId id) {
|
tp::String getSongLocalPath(SongId id) { return getHome() + "tracks/" + tp::String((tp::alni) id); }
|
||||||
return getHome() + "tracks/" + tp::String((tp::alni)id);
|
|
||||||
}
|
|
||||||
|
|
||||||
SONG_FORMAT getSongFormat(const String& localPath) {
|
SONG_FORMAT getSongFormat(const String& localPath) {
|
||||||
std::filesystem::path wavFormat((localPath + ".wav").read());
|
std::filesystem::path wavFormat((localPath + ".wav").read());
|
||||||
|
|
@ -61,16 +60,19 @@ bool Library::loadJson(const String& path) {
|
||||||
picojson::value jsonNode;
|
picojson::value jsonNode;
|
||||||
std::string err = picojson::parse(jsonNode, json);
|
std::string err = picojson::parse(jsonNode, json);
|
||||||
|
|
||||||
if (! err.empty()) {
|
if (!err.empty()) {
|
||||||
|
printf("Given path - %s\n", path.read());
|
||||||
|
printf("Home for library is - '%s'. Set it in the env as LIB_VIEW_HOME \n", getHome().read());
|
||||||
|
printf("Error parsing json library file - check your paths and files\n %s \n", err.c_str());
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto & traks = jsonNode.get<picojson::array>();
|
auto& traks = jsonNode.get<picojson::array>();
|
||||||
for (auto & trackNode : traks) {
|
for (auto& trackNode : traks) {
|
||||||
Track newTrack;
|
Track newTrack;
|
||||||
|
|
||||||
auto & track = trackNode.get<picojson::object>();
|
auto& track = trackNode.get<picojson::object>();
|
||||||
for (auto & trackProperty : track) {
|
for (auto& trackProperty : track) {
|
||||||
if (PROP(Name)) newTrack.mName = AS_STR;
|
if (PROP(Name)) newTrack.mName = AS_STR;
|
||||||
else if (PROP(Artist)) newTrack.mArtist = AS_STR;
|
else if (PROP(Artist)) newTrack.mArtist = AS_STR;
|
||||||
else if (PROP(Track ID)) newTrack.mId = AS_INT;
|
else if (PROP(Track ID)) newTrack.mId = AS_INT;
|
||||||
|
|
|
||||||
|
|
@ -4,95 +4,105 @@
|
||||||
#include "Player.hpp"
|
#include "Player.hpp"
|
||||||
#include "Widgets.hpp"
|
#include "Widgets.hpp"
|
||||||
|
|
||||||
template <typename Events, typename Canvas>
|
#include "imgui.h"
|
||||||
class ResizerWidget {
|
|
||||||
public:
|
|
||||||
ResizerWidget() = default;
|
|
||||||
|
|
||||||
void proc(const Events& events, const tp::RectF& areaParent, const tp::RectF& area) {
|
namespace tp {
|
||||||
if (!areaParent.isOverlap(area)) {
|
|
||||||
resizing = false;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
hover = area.isInside(events.getPos());
|
template <typename Events, typename Canvas>
|
||||||
|
class TrackWidget : public Widget<Events, Canvas> {
|
||||||
|
public:
|
||||||
|
explicit TrackWidget(const Track* track = nullptr) :
|
||||||
|
mTrack(track) {
|
||||||
|
this->mArea.w = 70;
|
||||||
|
col.mColor.setAnimTime(0);
|
||||||
|
col.mColor.setNoTransition({ 0.15f, 0.15f, 0.15f, 0.f });
|
||||||
|
};
|
||||||
|
|
||||||
if (events.isPressed() && hover) {
|
void proc(const Events& events, const RectF& areaParent, const RectF& area) override {
|
||||||
resizing = true;
|
mSelected = false;
|
||||||
} else if (!events.isDown()) {
|
this->mArea = area;
|
||||||
resizing = false;
|
this->mVisible = area.isOverlap(areaParent);
|
||||||
}
|
if (!this->mVisible) return;
|
||||||
|
|
||||||
value = area.x;
|
if (!mTrack) return;
|
||||||
|
|
||||||
if (resizing) {
|
|
||||||
tp::halnf pos = events.getPos().x;
|
|
||||||
auto diff = (pos - value - area.z / 2.f);
|
|
||||||
value += diff;
|
|
||||||
}
|
|
||||||
|
|
||||||
value = tp::clamp(value, min, max);
|
|
||||||
|
|
||||||
if (min > max) {
|
|
||||||
value = min;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void draw(Canvas& canvas, const tp::RectF& areaParent, const tp::RectF& area) {
|
|
||||||
if (!areaParent.isOverlap(area)) return;
|
if (!areaParent.isOverlap(area)) return;
|
||||||
|
if (area.isInside(events.getPos())) {
|
||||||
if (hover || resizing) {
|
col.set({ 0.15f, 0.15f, 0.15f, 1.f });
|
||||||
canvas.rect(area, { 0.23f, 0.23f, 0.23f, 1.f }, 0.f);
|
mSelected = events.isReleased();
|
||||||
} else {
|
} else {
|
||||||
canvas.rect(area, { 0.04f, 0.04f, 0.04f, 1.f }, 0.f);
|
col.set({ 0.15f, 0.15f, 0.15f, 0.f });
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public:
|
void draw(Canvas& canvas) const override {
|
||||||
bool hover = false;
|
if (!this->mVisible) return;
|
||||||
bool resizing = false;
|
if (!mTrack) return;
|
||||||
tp::halnf max = 0;
|
|
||||||
tp::halnf min = 0;
|
|
||||||
tp::halnf value = 0;
|
|
||||||
};
|
|
||||||
|
|
||||||
template <typename Events, typename Canvas>
|
canvas.rect(this->mArea, col.get(), 4.f);
|
||||||
requires(DrawableConcept<Canvas>)
|
|
||||||
class TrackInfoWidget {
|
const RectF imageArea = {
|
||||||
|
this->mArea.x + margin, this->mArea.y + margin, this->mArea.w - margin * 2, this->mArea.w - margin * 2
|
||||||
|
};
|
||||||
|
|
||||||
|
canvas.rect(imageArea, { 0.25f, 0.25f, 0.25f, 1.f }, 4.f);
|
||||||
|
|
||||||
|
const RectF textArea = { this->mArea.x + this->mArea.w + margin,
|
||||||
|
this->mArea.y + margin,
|
||||||
|
this->mArea.z - this->mArea.w - margin * 2,
|
||||||
|
this->mArea.w - margin * 2 };
|
||||||
|
|
||||||
|
// canvas.rect(textArea, { 0.25f, 0.25f, 0.25f, 1.f }, 4.f);
|
||||||
|
|
||||||
|
const RectF textAreaName = { textArea.x, textArea.y, textArea.z, textArea.w * 0.5f };
|
||||||
|
const RectF textAreaAuthor = { textArea.x, textArea.y + textArea.w * 0.5f, textArea.z, textArea.w * 0.5f };
|
||||||
|
|
||||||
|
canvas.text(mTrack->mName.read(), textAreaName, 15.f, Canvas::LC, 4.f, { 0.9f, 0.9f, 0.9f, 1.f });
|
||||||
|
canvas.text(mTrack->mArtist.read(), textAreaAuthor, 12.f, Canvas::LC, 4.f, { 0.8f, 0.8f, 0.8f, 1.f });
|
||||||
|
}
|
||||||
|
|
||||||
|
public:
|
||||||
|
halnf margin = 5.f;
|
||||||
|
AnimColor col;
|
||||||
|
const Track* mTrack;
|
||||||
|
bool mSelected = false;
|
||||||
|
};
|
||||||
|
|
||||||
|
template <typename Events, typename Canvas>
|
||||||
|
class TrackInfoWidget : public Widget<Events, Canvas> {
|
||||||
struct SortType {
|
struct SortType {
|
||||||
tp::String text;
|
String text;
|
||||||
bool dec = false;
|
bool dec = false;
|
||||||
bool inc = false;
|
bool inc = false;
|
||||||
};
|
};
|
||||||
|
|
||||||
public:
|
public:
|
||||||
TrackInfoWidget(const Track* track = nullptr) :
|
explicit TrackInfoWidget(const Track* track = nullptr) :
|
||||||
mTrack(track) {
|
mTrack(track) {
|
||||||
items.append({ "Date Added" });
|
items.append({ "Date Added" });
|
||||||
items.append({ "Date Last Played" });
|
items.append({ "Date Last Played" });
|
||||||
}
|
}
|
||||||
|
|
||||||
void proc(const Events& events, const tp::RectF& areaParent, const tp::RectF& area) {
|
void proc(const Events&, const RectF& areaParent, const RectF& area) override {
|
||||||
|
this->mArea = area;
|
||||||
|
this->mVisible = area.isOverlap(areaParent);
|
||||||
|
if (!this->mVisible) return;
|
||||||
if (!mTrack) return;
|
if (!mTrack) return;
|
||||||
if (!areaParent.isOverlap(area)) return;
|
// renderUI();
|
||||||
}
|
}
|
||||||
|
|
||||||
void draw(Canvas& canvas, const tp::RectF& areaParent, const tp::RectF& area) {
|
void draw(Canvas&) const override {
|
||||||
if (!areaParent.isOverlap(area)) return;
|
if (!this->mVisible) return;
|
||||||
|
|
||||||
ImGui::SetNextWindowPos({ area.x, area.y });
|
|
||||||
ImGui::SetNextWindowSize({ area.z, area.w });
|
|
||||||
RenderUI();
|
|
||||||
|
|
||||||
canvas.rect(area, { 0.13f, 0.13f, 0.13f, 1.f }, 4.f);
|
|
||||||
|
|
||||||
if (!mTrack) return;
|
if (!mTrack) return;
|
||||||
|
// canvas.rect(this->mArea, { 0.13f, 0.13f, 0.13f, 1.f }, 4.f);
|
||||||
}
|
}
|
||||||
|
|
||||||
void RenderUI() {
|
void renderUI() {
|
||||||
|
ImGui::SetNextWindowPos({ this->mArea.x, this->mArea.y });
|
||||||
|
ImGui::SetNextWindowSize({ this->mArea.z, this->mArea.w });
|
||||||
|
|
||||||
ImGui::Begin(
|
ImGui::Begin(
|
||||||
"InfoWindow",
|
"InfoWindow",
|
||||||
0,
|
nullptr,
|
||||||
ImGuiWindowFlags_NoTitleBar | ImGuiWindowFlags_NoCollapse | ImGuiWindowFlags_NoBackground |
|
ImGuiWindowFlags_NoTitleBar | ImGuiWindowFlags_NoCollapse | ImGuiWindowFlags_NoBackground |
|
||||||
ImGuiWindowFlags_NoResize
|
ImGuiWindowFlags_NoResize
|
||||||
);
|
);
|
||||||
|
|
@ -137,7 +147,7 @@ public:
|
||||||
ImGui::Text("Play Count : %lli", mTrack->mPlayCount);
|
ImGui::Text("Play Count : %lli", mTrack->mPlayCount);
|
||||||
ImGui::Text("Skip Count : %lli", mTrack->mSkipCount);
|
ImGui::Text("Skip Count : %lli", mTrack->mSkipCount);
|
||||||
ImGui::Text("Date Added : %s", mTrack->mDateAdded.read());
|
ImGui::Text("Date Added : %s", mTrack->mDateAdded.read());
|
||||||
ImGui::Text("Albom : %s", mTrack->mAlbum.read());
|
ImGui::Text("Album : %s", mTrack->mAlbum.read());
|
||||||
} else {
|
} else {
|
||||||
ImGui::Text("Not Selected");
|
ImGui::Text("Not Selected");
|
||||||
}
|
}
|
||||||
|
|
@ -178,237 +188,76 @@ public:
|
||||||
ImGui::End();
|
ImGui::End();
|
||||||
}
|
}
|
||||||
|
|
||||||
public:
|
public:
|
||||||
ImGuiTextFilter songFilter;
|
ImGuiTextFilter songFilter{};
|
||||||
ImGuiTextFilter sortFilter;
|
ImGuiTextFilter sortFilter{};
|
||||||
tp::Buffer<SortType> items;
|
Buffer<SortType> items;
|
||||||
const Track* mTrack;
|
const Track* mTrack;
|
||||||
bool filterLoved = false;
|
bool filterLoved = false;
|
||||||
Player* mPlayer = nullptr;
|
Player* mPlayer = nullptr;
|
||||||
bool mLoadStatus = false;
|
bool mLoadStatus = false;
|
||||||
bool isSongFilterChanged = true;
|
bool isSongFilterChanged = true;
|
||||||
int filterExisting = 0; // all existing no-existing
|
int filterExisting = 0; // all existing no-existing
|
||||||
};
|
|
||||||
|
|
||||||
template <typename Events, typename Canvas>
|
|
||||||
requires(DrawableConcept<Canvas>)
|
|
||||||
class ScrollBarWidget {
|
|
||||||
public:
|
|
||||||
ScrollBarWidget() = default;
|
|
||||||
|
|
||||||
void proc(const Events& events, const tp::RectF& areaParent, const tp::RectF& area) {
|
|
||||||
if (mSizeFraction > 1.f) {
|
|
||||||
mPositionFraction = 0;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!areaParent.isOverlap(area)) {
|
|
||||||
mIsScrolling = false;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (events.getScrollY() != 0 && areaParent.isInside(events.getPos())) {
|
|
||||||
auto offset = events.getScrollY() < 0 ? 1.0f : -1.0f;
|
|
||||||
if (scrollInertia * offset > 0) {
|
|
||||||
scrollInertia += offset;
|
|
||||||
} else {
|
|
||||||
scrollInertia = -scrollInertia + offset;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (tp::abs(scrollInertia) > 0.1f) {
|
|
||||||
auto offset = scrollInertia * mScrollFactor;
|
|
||||||
mPositionFraction += offset;
|
|
||||||
mPositionFraction = tp::clamp(mPositionFraction, 0.f, 1.f - mSizeFraction);
|
|
||||||
scrollInertia *= 0.f;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (events.isPressed() && area.isInside(events.getPos())) {
|
|
||||||
mIsScrolling = true;
|
|
||||||
} else if (!events.isDown()) {
|
|
||||||
mIsScrolling = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (mIsScrolling) {
|
|
||||||
tp::halnf pos = events.getPos().y;
|
|
||||||
pos = (pos - area.y - mSizeFraction * area.w / 2.f) / area.w;
|
|
||||||
mPositionFraction = tp::clamp(pos, 0.f, 1.f - mSizeFraction);
|
|
||||||
}
|
|
||||||
|
|
||||||
mPositionFraction = tp::clamp(mPositionFraction, 0.f, 1.f - mSizeFraction);
|
|
||||||
}
|
|
||||||
|
|
||||||
void draw(Canvas& canvas, const tp::RectF& areaParent, const tp::RectF& area) {
|
|
||||||
if (mSizeFraction > 1.f) return;
|
|
||||||
if (!areaParent.isOverlap(area)) return;
|
|
||||||
|
|
||||||
auto minSize = 10.f;
|
|
||||||
tp::RGBA col = tp::RGBA{ 0.25f, 0.25f, 0.25f, 1.f };
|
|
||||||
|
|
||||||
if (mIsScrolling) {
|
|
||||||
col = tp::RGBA{ 0.45f, 0.45f, 0.45f, 1.f };
|
|
||||||
minSize = 20.f;
|
|
||||||
}
|
|
||||||
|
|
||||||
canvas.rect(area, { 0.15f, 0.15f, 0.15f, 1.f }, 4.f);
|
|
||||||
auto sliderSize = tp::clamp(area.w * mSizeFraction, minSize, area.w);
|
|
||||||
auto diffSize = sliderSize - area.w * mSizeFraction;
|
|
||||||
canvas.rect({ area.x, area.y + (area.w - diffSize) * mPositionFraction, area.z, sliderSize }, col, 4.f);
|
|
||||||
}
|
|
||||||
|
|
||||||
public:
|
|
||||||
tp::halnf mScrollFactor = 0.f;
|
|
||||||
tp::halnf scrollInertia = 0.f;
|
|
||||||
bool mIsScrolling = false;
|
|
||||||
tp::halnf mSizeFraction = 1.f;
|
|
||||||
tp::halnf mPositionFraction = 0.f;
|
|
||||||
};
|
|
||||||
|
|
||||||
template <typename Events, typename Canvas>
|
|
||||||
requires(DrawableConcept<Canvas>)
|
|
||||||
class TrackWidget {
|
|
||||||
public:
|
|
||||||
TrackWidget(const Track* track = nullptr) :
|
|
||||||
mTrack(track) {
|
|
||||||
col.mColor.setAnimTime(0);
|
|
||||||
col.mColor.setNoTransition({ 0.15f, 0.15f, 0.15f, 0.f });
|
|
||||||
};
|
};
|
||||||
|
|
||||||
void proc(const Events& events, const tp::RectF& areaParent, const tp::RectF& area) {
|
template <typename Events, typename Canvas>
|
||||||
if (!mTrack) return;
|
class LibraryWidget : public Widget<Events, Canvas> {
|
||||||
if (!areaParent.isOverlap(area)) return;
|
public:
|
||||||
if (area.isInside(events.getPos())) {
|
LibraryWidget(Library* lib, Player* player) {
|
||||||
col.set({ 0.15f, 0.15f, 0.15f, 1.f });
|
mLibrary = (lib);
|
||||||
insideDebug = true;
|
mPlayer = (player);
|
||||||
} else {
|
|
||||||
col.set({ 0.15f, 0.15f, 0.15f, 0.f });
|
|
||||||
insideDebug = false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void draw(Canvas& canvas, const tp::RectF& areaParent, const tp::RectF& area) {
|
|
||||||
if (!mTrack) return;
|
|
||||||
if (!areaParent.isOverlap(area)) return;
|
|
||||||
|
|
||||||
canvas.rect(area, col.get(), 4.f);
|
|
||||||
|
|
||||||
const tp::RectF imageArea = { area.x + marging, area.y + marging, area.w - marging * 2, area.w - marging * 2 };
|
|
||||||
canvas.rect(imageArea, { 0.25f, 0.25f, 0.25f, 1.f }, 4.f);
|
|
||||||
|
|
||||||
const tp::RectF textArea = {
|
|
||||||
area.x + area.w + marging, area.y + marging, area.z - area.w - marging * 2, area.w - marging * 2
|
|
||||||
};
|
|
||||||
// canvas.rect(textArea, { 0.25f, 0.25f, 0.25f, 1.f }, 4.f);
|
|
||||||
|
|
||||||
const tp::RectF textAreaName = { textArea.x, textArea.y, textArea.z, textArea.w * 0.5f };
|
|
||||||
const tp::RectF textAreaAuthor = { textArea.x, textArea.y + textArea.w * 0.5f, textArea.z, textArea.w * 0.5f };
|
|
||||||
|
|
||||||
canvas.text(mTrack->mName.read(), textAreaName, 15.f, Canvas::LC, 4.f, { 0.9f, 0.9f, 0.9f, 1.f });
|
|
||||||
canvas.text(mTrack->mArtist.read(), textAreaAuthor, 12.f, Canvas::LC, 4.f, { 0.8f, 0.8f, 0.8f, 1.f });
|
|
||||||
}
|
|
||||||
|
|
||||||
public:
|
|
||||||
tp::halnf marging = 5.f;
|
|
||||||
bool insideDebug = false;
|
|
||||||
tp::AnimColor col;
|
|
||||||
const Track* mTrack;
|
|
||||||
};
|
|
||||||
|
|
||||||
template <typename Events, typename Canvas>
|
|
||||||
requires(DrawableConcept<Canvas>)
|
|
||||||
class LibraryWidget {
|
|
||||||
public:
|
|
||||||
LibraryWidget(Library* lib, Player* player) :
|
|
||||||
mLibrary(lib),
|
|
||||||
mPlayer(player) {
|
|
||||||
for (auto track : mLibrary->mTraks) {
|
for (auto track : mLibrary->mTraks) {
|
||||||
mTraks.append(TrackWidget<Events, Canvas>(&track.data()));
|
mTracks.append(TrackWidget<Events, Canvas>(&track.data()));
|
||||||
}
|
}
|
||||||
mResizeWidget.value = 1000;
|
|
||||||
mCurrentTrackInfo.mPlayer = mPlayer;
|
mCurrentTrackInfo.mPlayer = mPlayer;
|
||||||
}
|
}
|
||||||
|
|
||||||
void proc(const Events& events, const tp::RectF& areaParent, const tp::RectF& aArea) {
|
void proc(const Events& events, const RectF& areaParent, const RectF& aArea) override {
|
||||||
|
this->mArea = aArea;
|
||||||
|
this->mVisible = this->mArea.isOverlap(areaParent);
|
||||||
|
if (!this->mVisible) return;
|
||||||
|
|
||||||
|
mCurrentTrackInfo.renderUI();
|
||||||
mNeedRedraw = events.isEvent() || mCurrentTrackInfo.songFilter.IsActive();
|
mNeedRedraw = events.isEvent() || mCurrentTrackInfo.songFilter.IsActive();
|
||||||
|
|
||||||
if (!mNeedRedraw) return;
|
if (!mNeedRedraw) return;
|
||||||
|
|
||||||
filter();
|
filter();
|
||||||
|
|
||||||
mResizeWidget.max = aArea.z - trackInfoSize;
|
mSplitView.proc(events, this->mArea, this->mArea);
|
||||||
mResizeWidget.min = 100;
|
mSongList.proc(events, this->mArea, mSplitView.getFirst());
|
||||||
|
|
||||||
areaCP = { aArea.x, aArea.y + aArea.w - controllPanelSize, aArea.z, controllPanelSize };
|
for (auto track : mSongList.mContents) {
|
||||||
area = { aArea.x, aArea.y, mResizeWidget.value, aArea.w - controllPanelSize };
|
auto trackWidget = (TrackWidget<Events, Canvas>*) track.data();
|
||||||
areaInfo = {
|
if (trackWidget->mSelected) {
|
||||||
mResizeWidget.value + resizeSize, aArea.y, aArea.z - mResizeWidget.value - resizeSize, aArea.w - controllPanelSize
|
mCurrentTrackInfo.mTrack = trackWidget->mTrack;
|
||||||
};
|
|
||||||
areaResize = { mResizeWidget.value, aArea.y, resizeSize, areaInfo.w };
|
|
||||||
|
|
||||||
mScroll.mSizeFraction = (area.w - 10) / (mTraksFiltered.size() * trackSize);
|
|
||||||
mScroll.mScrollFactor = 1.f / mTraksFiltered.size();
|
|
||||||
|
|
||||||
mScroll.proc(events, area, { area.x + area.z - scrollSize - 3, area.y + 10, scrollSize - 3.f, area.w - 20 });
|
|
||||||
mResizeWidget.proc(events, area, areaResize);
|
|
||||||
|
|
||||||
if (area.isInside(events.getPos())) {
|
|
||||||
|
|
||||||
tp::halnf offset = mScroll.mPositionFraction * mTraksFiltered.size() * trackSize;
|
|
||||||
auto idx = 0;
|
|
||||||
|
|
||||||
for (auto track : mTraksFiltered) {
|
|
||||||
auto trackArea =
|
|
||||||
tp::RectF{ area.x + 10, area.y + 10 + idx * trackSize - offset, area.z - 20 - scrollSize, trackSize - 5 };
|
|
||||||
|
|
||||||
track->proc(events, area, trackArea);
|
|
||||||
|
|
||||||
if (trackArea.isInside(events.getPos()) && events.isPressed()) {
|
|
||||||
mCurrentTrack.mTrack = track->mTrack;
|
|
||||||
mCurrentTrackInfo.mTrack = track->mTrack;
|
|
||||||
}
|
|
||||||
|
|
||||||
idx++;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
debugPos = events.getPos();
|
mCurrentTrackInfo.proc(events, this->mArea, mSplitView.getSecond());
|
||||||
|
|
||||||
|
// mCurrentTrack.proc(events, this->mArea, mSplitView.getFirst());
|
||||||
}
|
}
|
||||||
|
|
||||||
void draw(Canvas& canvas, const tp::RectF& areaParent, const tp::RectF& aArea) {
|
void draw(Canvas& canvas) const override {
|
||||||
|
if (!this->mVisible) return;
|
||||||
|
|
||||||
canvas.rect(aArea, { 0.1f, 0.1f, 0.1f, 1.f });
|
canvas.rect(this->mArea, { 0.1f, 0.1f, 0.1f, 1.f });
|
||||||
|
|
||||||
tp::halnf offset = mScroll.mPositionFraction * mTraksFiltered.size() * trackSize;
|
mSplitView.draw(canvas);
|
||||||
auto idx = 0;
|
mSongList.draw(canvas);
|
||||||
|
mCurrentTrackInfo.draw(canvas);
|
||||||
for (auto track : mTraksFiltered) {
|
// mCurrentTrack.proc(canvas);
|
||||||
auto const trackArea =
|
|
||||||
tp::RectF{ area.x + 10, area.y + 10 + idx * trackSize - offset, area.z - 20 - scrollSize, trackSize - 5 };
|
|
||||||
if (track->mTrack == mCurrentTrack.mTrack) canvas.rect(trackArea, { 0.2f, 0.2f, 0.2f, 0.5f }, 5);
|
|
||||||
track->draw(canvas, area, trackArea);
|
|
||||||
idx++;
|
|
||||||
}
|
|
||||||
|
|
||||||
mScroll.draw(canvas, area, { area.x + area.z - scrollSize - 3, area.y + 10, scrollSize - 3.f, area.w - 20 });
|
|
||||||
|
|
||||||
// canvas.rect( areaInfo, { 0.04f, 0.04f, 0.04f, 1.f });
|
|
||||||
mCurrentTrackInfo.draw(canvas, aArea, areaInfo);
|
|
||||||
|
|
||||||
mResizeWidget.draw(canvas, aArea, areaResize);
|
|
||||||
|
|
||||||
drawCP(canvas, aArea, areaCP);
|
|
||||||
}
|
|
||||||
|
|
||||||
void drawCP(Canvas& canvas, const tp::RectF& areaParent, const tp::RectF& area) {
|
|
||||||
canvas.rect(area, { 0.04f, 0.04f, 0.04f, 1.f });
|
|
||||||
mCurrentTrack.draw(canvas, area, area);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void filter() {
|
void filter() {
|
||||||
if (!mCurrentTrackInfo.isSongFilterChanged) return;
|
if (!mCurrentTrackInfo.isSongFilterChanged) return;
|
||||||
mTraksFiltered.clear();
|
|
||||||
|
|
||||||
for (auto track : mTraks) {
|
mSongList.mContents.clear();
|
||||||
|
|
||||||
|
for (auto track : mTracks) {
|
||||||
if (!mCurrentTrackInfo.songFilter.PassFilter(track->mTrack->mName.read()) && !mCurrentTrackInfo.songFilter.PassFilter(track->mTrack->mArtist.read())) {
|
if (!mCurrentTrackInfo.songFilter.PassFilter(track->mTrack->mName.read()) && !mCurrentTrackInfo.songFilter.PassFilter(track->mTrack->mArtist.read())) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
@ -427,36 +276,23 @@ public:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
mTraksFiltered.append(&track.data());
|
mSongList.mContents.append(&track.data());
|
||||||
}
|
}
|
||||||
|
|
||||||
mCurrentTrackInfo.isSongFilterChanged = false;
|
mCurrentTrackInfo.isSongFilterChanged = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
tp::halnf scrollSize = 20;
|
Library* mLibrary = nullptr;
|
||||||
tp::halnf trackInfoSize = 200;
|
Player* mPlayer = nullptr;
|
||||||
tp::halnf controllPanelSize = 70;
|
|
||||||
tp::halnf trackSize = 60;
|
|
||||||
tp::Vec2F debugPos;
|
|
||||||
tp::halnf resizeSize = 10;
|
|
||||||
|
|
||||||
tp::RectF area;
|
Buffer<TrackWidget<Events, Canvas>> mTracks;
|
||||||
tp::RectF areaInfo;
|
|
||||||
tp::RectF areaCP;
|
|
||||||
tp::RectF areaResize;
|
|
||||||
|
|
||||||
tp::Buffer<TrackWidget<Events, Canvas>> mTraks;
|
SplitView<Events, Canvas> mSplitView;
|
||||||
tp::Buffer<TrackWidget<Events, Canvas>*> mTraksFiltered;
|
ScrollableWindow<Events, Canvas> mSongList;
|
||||||
|
|
||||||
TrackWidget<Events, Canvas> mCurrentTrack;
|
|
||||||
TrackInfoWidget<Events, Canvas> mCurrentTrackInfo;
|
TrackInfoWidget<Events, Canvas> mCurrentTrackInfo;
|
||||||
|
TrackWidget<Events, Canvas> mCurrentTrack;
|
||||||
ScrollBarWidget<Events, Canvas> mScroll;
|
|
||||||
ResizerWidget<Events, Canvas> mResizeWidget;
|
|
||||||
|
|
||||||
Library* mLibrary;
|
|
||||||
Player* mPlayer;
|
|
||||||
|
|
||||||
bool mNeedRedraw = false;
|
bool mNeedRedraw = false;
|
||||||
};
|
};
|
||||||
|
}
|
||||||
|
|
@ -197,7 +197,7 @@ namespace tp {
|
||||||
const auto padding = this->getValue("Padding");
|
const auto padding = this->getValue("Padding");
|
||||||
mContentSize = mContents.last()->mArea.y - mContents.first()->mArea.y;
|
mContentSize = mContents.last()->mArea.y - mContents.first()->mArea.y;
|
||||||
mContentSize += mContents.last()->mArea.w;
|
mContentSize += mContents.last()->mArea.w;
|
||||||
mContentSize += (mContents.size()) * padding;
|
mContentSize += 2 * padding;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue