big time refactor + button styles
This commit is contained in:
@@ -51,7 +51,7 @@ public:
|
||||
bool showDisabledDevices = false;
|
||||
bool showChecklistExtras = false;
|
||||
std::vector<std::string> taskNames = {};
|
||||
std::unordered_map<std::string, std::vector<time_t>> tasks = {};
|
||||
std::unordered_map<std::string, std::vector<std::chrono::year_month_day>> tasks = {};
|
||||
std::vector<std::string> baseStationMacAdresses = {};
|
||||
bool baseStationShowConsole;
|
||||
float timerDuration = 5.f * 60.f;
|
||||
@@ -80,7 +80,7 @@ public:
|
||||
int checklistHighlightDurationDays = 3;
|
||||
std::shared_ptr<AudioData> audioData = std::make_shared<AudioData>();
|
||||
HoverTargetType hoverTargetType = HoverTargetType::HOVER_TARGET_NONE;
|
||||
time_t hoverTargetDay = 0;
|
||||
std::chrono::year_month_day hoverTargetDay = {};
|
||||
TimerData timerData{};
|
||||
std::mutex timerMutex{};
|
||||
bool lighthouseProcActive = false;
|
||||
|
||||
@@ -21,8 +21,10 @@
|
||||
#include <iostream>
|
||||
#include <sstream>
|
||||
#include <format>
|
||||
#include <ctime>
|
||||
using std::chrono::year_month_day;
|
||||
|
||||
#undef min
|
||||
#undef max
|
||||
|
||||
#define MAX_FONT_PATH_LENGTH 2048
|
||||
#define SETTINGS_POPUP_NAME "settings_popup"
|
||||
@@ -33,7 +35,7 @@ DrawData* gDrawData;
|
||||
ApplicationData* gAppData;
|
||||
bool justDocked = false;
|
||||
bool isHidden = false;
|
||||
time_t selectedDay = 0;
|
||||
year_month_day selectedDay = {};
|
||||
|
||||
int main()
|
||||
{
|
||||
@@ -56,36 +58,6 @@ int main()
|
||||
startImgui(callbacks, "Audio Thingy", 700, 400);
|
||||
}
|
||||
|
||||
time_t getDayStartOf(time_t time)
|
||||
{
|
||||
tm localTime;
|
||||
localtime_s(&localTime, &time);
|
||||
localTime.tm_hour = 0;
|
||||
localTime.tm_min = 0;
|
||||
localTime.tm_sec = 0;
|
||||
return mktime(&localTime);
|
||||
}
|
||||
|
||||
void dropShadow(float size, ImColor color)
|
||||
{
|
||||
ImDrawList* windowDrawList = ImGui::GetWindowDrawList();
|
||||
ImVec2 lastMin = ImGui::GetItemRectMin();
|
||||
ImVec2 lastMax = ImGui::GetItemRectMax();
|
||||
|
||||
windowDrawList->AddQuadFilled(
|
||||
{ lastMin.x, lastMax.y },
|
||||
{ lastMax.x, lastMax.y },
|
||||
{ lastMax.x + size, lastMax.y + size },
|
||||
{ lastMin.x + size, lastMax.y + size },
|
||||
color);
|
||||
windowDrawList->AddQuadFilled(
|
||||
{ lastMax.x, lastMin.y },
|
||||
{ lastMax.x + size, lastMin.y + size },
|
||||
{ lastMax.x + size, lastMax.y + size },
|
||||
{ lastMax.x, lastMax.y },
|
||||
color);
|
||||
}
|
||||
|
||||
void init(DrawData& drawData, ApplicationData& appData)
|
||||
{
|
||||
std::wstring appPath;
|
||||
@@ -122,7 +94,7 @@ void init(DrawData& drawData, ApplicationData& appData)
|
||||
timerThread.detach();
|
||||
|
||||
// Time
|
||||
selectedDay = getDayStartOf(std::time(nullptr));
|
||||
selectedDay = std::chrono::floor<std::chrono::days>(std::chrono::system_clock::now());
|
||||
|
||||
initShell(drawData);
|
||||
initSettings(drawData, appData);
|
||||
@@ -156,14 +128,14 @@ void draw(DrawData& drawData, ApplicationData& appData)
|
||||
|
||||
// Timer
|
||||
ImGui::SetNextWindowPos(ImVec2(0, customYCursor));
|
||||
ImGui::SetNextWindowSize(ImVec2(viewportSize.x / 2.f, 0));
|
||||
ImGui::SetNextWindowSize(ImVec2(viewportSize.x / 2.f - 1.f, 0));
|
||||
float timerWindowHeight = timerWindow(drawData, appData).y;
|
||||
|
||||
// Base Stations
|
||||
ImGui::SetNextWindowPos(ImVec2(viewportSize.x / 2.f, customYCursor));
|
||||
ImGui::SetNextWindowSize(ImVec2(viewportSize.x / 2.f, 0));
|
||||
ImGui::SetNextWindowSize(ImVec2(viewportSize.x / 2.f - 1.f, 0));
|
||||
float baseStationWindowHeight = baseStationWindow(appData).y;
|
||||
customYCursor += max(baseStationWindowHeight, timerWindowHeight);
|
||||
customYCursor += std::fmaxf(baseStationWindowHeight, timerWindowHeight);
|
||||
customYCursor += panelGap;
|
||||
|
||||
// Playback Devices
|
||||
@@ -187,14 +159,12 @@ void draw(DrawData& drawData, ApplicationData& appData)
|
||||
glfwSetWindowPos(drawData.window, monitorX + monitorW - drawData.window_size.x, monitorY + monitorH - drawData.window_size.y);
|
||||
}
|
||||
|
||||
// Tooltip
|
||||
if (appData.hoverTargetType == HoverTargetType::HOVER_TARGET_CHECKLIST_DAY)
|
||||
{
|
||||
tm time_tm;
|
||||
localtime_s(&time_tm, &appData.hoverTargetDay);
|
||||
|
||||
ImGui::BeginTooltip();
|
||||
char timeStr[32];
|
||||
strftime(timeStr, 32, "%d.%m", &time_tm);
|
||||
snprintf(timeStr, _countof(timeStr), "%02u.%02u", unsigned int{ appData.hoverTargetDay.day() }, unsigned int{ appData.hoverTargetDay.month() });
|
||||
ImGui::Text(timeStr);
|
||||
ImGui::EndTooltip();
|
||||
}
|
||||
@@ -290,7 +260,7 @@ bool customButton(const char* id_start, const char* id_end, const char* title, b
|
||||
if (visible)
|
||||
{
|
||||
ImGui::PushID(buttonId.c_str());
|
||||
result = ImGui::SmallButton(title);
|
||||
result = dropButton(title, {}, 2.f, true);
|
||||
ImGui::PopID();
|
||||
}
|
||||
else
|
||||
@@ -308,8 +278,9 @@ bool windowHeaderButton(const char* id)
|
||||
ImVec2 windowMax = ImGui::GetWindowContentRegionMax();
|
||||
ImGui::PopClipRect();
|
||||
|
||||
ImGui::SetCursorPos({ windowMax.x - getButtonWidth(ICON_CLOSE_FILL), tempPos.y - 30.f});
|
||||
bool result = ImGui::SmallButton(id);
|
||||
ImGuiStyle style = ImGui::GetStyle();
|
||||
ImGui::SetCursorPos({ windowMax.x - getButtonWidth(ICON_CLOSE_FILL), tempPos.y - style.WindowPadding.y - 22.f });
|
||||
bool result = dropButton(id, ImVec2{}, 1.f, true);
|
||||
|
||||
ImGui::PushClipRect(tempRect.Min, tempRect.Max, false);
|
||||
ImGui::SetCursorPos(tempPos);
|
||||
@@ -317,26 +288,29 @@ bool windowHeaderButton(const char* id)
|
||||
return result;
|
||||
}
|
||||
|
||||
void drawChecklistDayLines(ApplicationData& appData, ImDrawList* drawList, float lineHeight, time_t day)
|
||||
void drawChecklistDayLines(ApplicationData& appData, ImDrawList* drawList, float lineHeight, year_month_day day)
|
||||
{
|
||||
auto& tasks = appData.settings.tasks;
|
||||
size_t totalTasks = appData.settings.taskNames.size();
|
||||
size_t count = std::count_if(tasks.begin(), tasks.end(), [&](std::pair<std::string, std::vector<time_t>> t) { return std::any_of(t.second.begin(), t.second.end(), [&](time_t tt) { return tt == day; }); });
|
||||
for (int i = 0; i < count; i++)
|
||||
for (std::string& taskName : appData.settings.taskNames)
|
||||
{
|
||||
ImVec2 cursorPos = ImGui::GetCursorScreenPos();
|
||||
drawList->AddLine({ cursorPos.x, cursorPos.y }, { cursorPos.x, cursorPos.y + lineHeight }, ImColor(.4f, .9f, .3f), DAY_LINE_WIDTH);
|
||||
ImGui::SetCursorScreenPos({ cursorPos.x + DAY_LINE_OFFSET, cursorPos.y });
|
||||
}
|
||||
for (int i = 0; i < max(0, totalTasks - count); i++)
|
||||
{
|
||||
ImVec2 cursorPos = ImGui::GetCursorScreenPos();
|
||||
drawList->AddLine({ cursorPos.x, cursorPos.y }, { cursorPos.x, cursorPos.y + lineHeight }, ImColor(.1f, .3f, .05f), DAY_LINE_WIDTH);
|
||||
ImColor color;
|
||||
auto& tasks = appData.settings.tasks[taskName];
|
||||
|
||||
if (std::any_of(tasks.begin(), tasks.end(), [&](year_month_day taskDay) { return taskDay == day; }))
|
||||
{
|
||||
color = ImColor{ .4f, .9f, .3f };
|
||||
}
|
||||
else
|
||||
{
|
||||
color = ImColor{ .1f, .3f, .05f };
|
||||
}
|
||||
|
||||
drawList->AddLine({ cursorPos.x, cursorPos.y }, { cursorPos.x, cursorPos.y + lineHeight }, color, DAY_LINE_WIDTH);
|
||||
ImGui::SetCursorScreenPos({ cursorPos.x + DAY_LINE_OFFSET, cursorPos.y });
|
||||
}
|
||||
}
|
||||
|
||||
void drawDayLineButton(ApplicationData& appData, ImDrawList* drawList, float lineHeight, time_t day, bool drawRect = true)
|
||||
void drawDayLineButton(ApplicationData& appData, ImDrawList* drawList, float lineHeight, year_month_day day, bool drawRect = true)
|
||||
{
|
||||
ImVec2 pos = ImGui::GetCursorScreenPos();
|
||||
ImVec2 startPos = { pos.x - DAY_OUTLINE_SIZE, pos.y - DAY_OUTLINE_SIZE };
|
||||
@@ -362,11 +336,11 @@ void drawDayLineButton(ApplicationData& appData, ImDrawList* drawList, float lin
|
||||
}
|
||||
}
|
||||
|
||||
void SetTimerDuration(ApplicationData& appData, int timerEndHours, int timerEndMinutes, tm& timeInfo)
|
||||
void setTimerDuration(ApplicationData& appData, int timerEndHours, int timerEndMinutes, tm& timeInfo)
|
||||
{
|
||||
timeInfo.tm_hour = timerEndHours;
|
||||
timeInfo.tm_min = timerEndMinutes;
|
||||
std::chrono::time_point<std::chrono::system_clock> newEndTime = std::chrono::system_clock::from_time_t(mktime(&timeInfo));
|
||||
TimePoint newEndTime = std::chrono::system_clock::from_time_t(mktime(&timeInfo));
|
||||
|
||||
if (newEndTime < std::chrono::system_clock::now())
|
||||
{
|
||||
@@ -443,7 +417,7 @@ ImVec2 timerWindow(DrawData& drawData, ApplicationData& appData)
|
||||
}
|
||||
|
||||
// Play/Reset
|
||||
if (ImGui::Button(timerData.isTimerActive ? ICON_RESTART_LINE : ICON_PLAY_FILL))
|
||||
if (dropButton(timerData.isTimerActive ? ICON_RESTART_LINE : ICON_PLAY_FILL))
|
||||
{
|
||||
if (!timerData.isTimerActive)
|
||||
{
|
||||
@@ -461,34 +435,31 @@ ImVec2 timerWindow(DrawData& drawData, ApplicationData& appData)
|
||||
ImGui::SameLine();
|
||||
ImGui::SetCursorPosX(ImGui::GetCursorPosX() + 5.f);
|
||||
|
||||
if (ImGui::Button(ICON_SUBTRACT_FILL))
|
||||
if (dropButton(ICON_SUBTRACT_FILL))
|
||||
{
|
||||
appData.settings.timerDuration -= 60.f;
|
||||
if (appData.settings.timerDuration < 0.) appData.settings.timerDuration = 0.f;
|
||||
}
|
||||
dropShadow(3.f, { 1.f, 1.f, 1.f, .3f });
|
||||
|
||||
ImGui::SameLine();
|
||||
const char* durationFormatStr = "%.0fm";
|
||||
char durationCalcBuffer[32];
|
||||
snprintf(durationCalcBuffer, 32, durationFormatStr, timerDisplayMinutes);
|
||||
|
||||
ImGui::PushItemWidth(ImGui::CalcTextSize(durationCalcBuffer).x + ImGui::GetStyle().FramePadding.x * 2.f);
|
||||
ImGui::PushItemWidth(calcInputWidth(durationFormatStr, timerDisplayMinutes));
|
||||
if (ImGui::DragFloat("##timer", &timerDisplayMinutes, .1f, 0.f, 1000.f, durationFormatStr))
|
||||
{
|
||||
appData.settings.timerDuration = timerDisplayMinutes * 60.f;
|
||||
}
|
||||
dropShadow();
|
||||
ImGui::PopItemWidth();
|
||||
|
||||
ImGui::SameLine();
|
||||
if (ImGui::Button(ICON_ADD_FILL))
|
||||
if (dropButton(ICON_ADD_FILL))
|
||||
{
|
||||
appData.settings.timerDuration += 60.f;
|
||||
}
|
||||
|
||||
ImGui::SameLine();
|
||||
|
||||
std::chrono::time_point<std::chrono::system_clock> endTime;
|
||||
TimePoint endTime;
|
||||
const char* endTimeText;
|
||||
|
||||
if (timerData.isTimerActive)
|
||||
@@ -510,39 +481,44 @@ ImVec2 timerWindow(DrawData& drawData, ApplicationData& appData)
|
||||
endTimeText = "Ends";
|
||||
}
|
||||
|
||||
const float timeDragWidth = 32.f;
|
||||
float requiredWidth = ImGui::CalcTextSize(endTimeText).x + timeDragWidth * 2.f + ImGui::GetStyle().ItemSpacing.x * 4.f;
|
||||
float spaceWidth = ImGui::GetContentRegionAvail().x - requiredWidth;
|
||||
ImGui::SetCursorPosX(ImGui::GetCursorPosX() + spaceWidth);
|
||||
|
||||
const time_t tTime = std::chrono::system_clock::to_time_t(endTime);
|
||||
tm timeInfo;
|
||||
localtime_s(&timeInfo, &tTime);
|
||||
int timerEndHours = timeInfo.tm_hour;
|
||||
int timerEndMinutes = timeInfo.tm_min;
|
||||
|
||||
const char* hourInputFormat = "%d";
|
||||
float hourDragWidth = calcInputWidth(hourInputFormat, timerEndHours);
|
||||
|
||||
const char* minuteInputFormat = "%02d";
|
||||
float minuteDragWidth = calcInputWidth(minuteInputFormat, timerEndMinutes);
|
||||
|
||||
ImGuiStyle style = ImGui::GetStyle();
|
||||
float requiredWidth = ImGui::CalcTextSize(endTimeText).x + style.ItemSpacing.x + hourDragWidth + style.ItemSpacing.x + minuteDragWidth + 2.f;
|
||||
float spaceWidth = ImGui::GetContentRegionAvail().x - requiredWidth;
|
||||
ImGui::SetCursorPosX(ImGui::GetCursorPosX() + spaceWidth);
|
||||
|
||||
ImGui::Text("%s", endTimeText);
|
||||
ImGui::SameLine();
|
||||
ImGui::PushItemWidth(timeDragWidth);
|
||||
if (ImGui::DragInt("##timerEndHours", &timerEndHours, .1f, 0, 23, "%d", ImGuiInputTextFlags_CharsDecimal))
|
||||
ImGui::SetNextItemWidth(hourDragWidth);
|
||||
if (ImGui::DragInt("##timerEndHours", &timerEndHours, .1f, 0, 23, hourInputFormat, ImGuiInputTextFlags_CharsDecimal))
|
||||
{
|
||||
SetTimerDuration(appData, timerEndHours, timerEndMinutes, timeInfo);
|
||||
setTimerDuration(appData, timerEndHours, timerEndMinutes, timeInfo);
|
||||
}
|
||||
dropShadow();
|
||||
|
||||
ImGui::SameLine();
|
||||
ImGui::Text(":");
|
||||
ImGui::SameLine();
|
||||
if (ImGui::DragInt("##timerEndMinutes", &timerEndMinutes, .2f, 0, 59, "%02d", ImGuiInputTextFlags_CharsDecimal))
|
||||
ImGui::SetNextItemWidth(minuteDragWidth);
|
||||
if (ImGui::DragInt("##timerEndMinutes", &timerEndMinutes, .2f, 0, 59, minuteInputFormat, ImGuiInputTextFlags_CharsDecimal))
|
||||
{
|
||||
SetTimerDuration(appData, timerEndHours, timerEndMinutes, timeInfo);
|
||||
setTimerDuration(appData, timerEndHours, timerEndMinutes, timeInfo);
|
||||
}
|
||||
ImGui::PopItemWidth();
|
||||
dropShadow();
|
||||
}
|
||||
|
||||
if (ImGui::BeginPopup(SETTINGS_POPUP_NAME))
|
||||
{
|
||||
// Loop
|
||||
//float loopContentWidth = ImGui::GetFrameHeight() + 5.f + ImGui::CalcTextSize("Loop").x + 5.f + 30.f + 10.f;
|
||||
//ImGui::SetCursorPosX(ImGui::GetWindowWidth() - loopContentWidth);
|
||||
ImGui::Checkbox("Loop", &appData.settings.timerRepeating);
|
||||
|
||||
ImGui::SameLine();
|
||||
@@ -572,13 +548,15 @@ ImVec2 checklistWindow(ApplicationData& appData, const char* title)
|
||||
ImGui::OpenPopup(SETTINGS_POPUP_NAME);
|
||||
}
|
||||
|
||||
time_t today = getDayStartOf(std::time(nullptr));
|
||||
// Previous days
|
||||
ImDrawList* drawList = ImGui::GetWindowDrawList();
|
||||
float lineHeight = ImGui::GetFontSize() + ImGui::GetStyle().FramePadding.y * 2;
|
||||
|
||||
for (int pastDay = 3; pastDay >= 1; pastDay--)
|
||||
{
|
||||
time_t date = today - (60 * 60 * 24 * pastDay);
|
||||
TimePoint now = std::chrono::system_clock::now();
|
||||
TimePoint selectedDay = now - std::chrono::days{ pastDay };
|
||||
year_month_day date = std::chrono::floor<std::chrono::days>(selectedDay);
|
||||
|
||||
drawDayLineButton(appData, drawList, lineHeight, date);
|
||||
drawChecklistDayLines(appData, drawList, lineHeight, date);
|
||||
@@ -586,37 +564,39 @@ ImVec2 checklistWindow(ApplicationData& appData, const char* title)
|
||||
ImGui::SetCursorPosX(ImGui::GetCursorPosX() + 5.f);
|
||||
}
|
||||
|
||||
// Current day
|
||||
ImVec2 cursorPos = ImGui::GetCursorScreenPos();
|
||||
drawList->AddLine({ cursorPos.x, cursorPos.y - 2.f }, { cursorPos.x, cursorPos.y + lineHeight + 2.f }, IM_COL32_WHITE, 1.f);
|
||||
|
||||
ImGui::SetCursorPosX(ImGui::GetCursorPosX() + 10.f);
|
||||
|
||||
year_month_day today = std::chrono::floor<std::chrono::days>(std::chrono::system_clock::now());
|
||||
drawDayLineButton(appData, drawList, lineHeight, today, false);
|
||||
drawChecklistDayLines(appData, drawList, lineHeight, today);
|
||||
|
||||
// Checkboxes
|
||||
ImGui::SetCursorPosX(ImGui::GetCursorPosX() + 10.f);
|
||||
|
||||
auto selectedDayMatcher = [&](time_t t) { return getDayStartOf(t) == selectedDay; };
|
||||
auto selectedDayMatcher = [&](year_month_day taskDay) { return taskDay == selectedDay; };
|
||||
|
||||
for (std::string& taskName : appData.settings.taskNames)
|
||||
{
|
||||
if (!appData.settings.tasks.contains(taskName))
|
||||
{
|
||||
appData.settings.tasks.insert({ taskName, std::vector<time_t>{} });
|
||||
appData.settings.tasks.insert({ taskName, std::vector<year_month_day>{} });
|
||||
}
|
||||
|
||||
std::vector<time_t>& taskDates = appData.settings.tasks[taskName];
|
||||
std::vector<year_month_day>& taskDates = appData.settings.tasks[taskName];
|
||||
bool taskDone = std::any_of(taskDates.begin(), taskDates.end(), selectedDayMatcher);
|
||||
bool highlightButton = false;
|
||||
std::string hoverText = "";
|
||||
|
||||
if (taskDates.size() > 0)
|
||||
{
|
||||
time_t mostRecentDoneDate = *std::max_element(taskDates.begin(), taskDates.end());
|
||||
double timeDiffSeconds = difftime(today, getDayStartOf(mostRecentDoneDate));
|
||||
int timeDiffDays = timeDiffSeconds / (60 * 60 * 24);
|
||||
highlightButton = timeDiffDays > appData.checklistHighlightDurationDays;
|
||||
hoverText = std::format("{}", timeDiffDays);
|
||||
year_month_day mostRecentDoneDate = *std::max_element(taskDates.begin(), taskDates.end());
|
||||
std::chrono::days timeDiffDays = std::chrono::round<std::chrono::days>(std::chrono::sys_days{ today } - std::chrono::sys_days{ mostRecentDoneDate });
|
||||
highlightButton = timeDiffDays > std::chrono::days{ appData.checklistHighlightDurationDays };
|
||||
hoverText = std::format("{}", timeDiffDays.count());
|
||||
}
|
||||
|
||||
if (highlightButton)
|
||||
@@ -628,7 +608,7 @@ ImVec2 checklistWindow(ApplicationData& appData, const char* title)
|
||||
|
||||
ImVec2 beforeCheckbox = ImGui::GetCursorScreenPos();
|
||||
std::string checkboxText = std::format("{}##taskcheck{}", taskName.c_str(), taskName.c_str());
|
||||
if (ImGui::Checkbox(checkboxText.c_str(), &taskDone))
|
||||
if (checkboxWithDropShadow(checkboxText.c_str(), &taskDone))
|
||||
{
|
||||
if (taskDone)
|
||||
{
|
||||
@@ -655,6 +635,7 @@ ImVec2 checklistWindow(ApplicationData& appData, const char* title)
|
||||
}
|
||||
}
|
||||
|
||||
// Popup
|
||||
if (ImGui::BeginPopup(SETTINGS_POPUP_NAME))
|
||||
{
|
||||
ImGui::Text("Task Highlight Duration");
|
||||
@@ -757,7 +738,7 @@ ImVec2 baseStationWindow(ApplicationData& appData)
|
||||
ImGui::OpenPopup(SETTINGS_POPUP_NAME);
|
||||
}
|
||||
|
||||
if (ImGui::Button("Wake"))
|
||||
if (dropButton("Wake"))
|
||||
{
|
||||
std::string params{ " on" };
|
||||
for (std::string& mac : appData.settings.baseStationMacAdresses)
|
||||
@@ -768,7 +749,7 @@ ImVec2 baseStationWindow(ApplicationData& appData)
|
||||
startBaseStationProc(appData, params.c_str(), appData.settings.baseStationShowConsole ? CREATE_NEW_CONSOLE : CREATE_NO_WINDOW);
|
||||
}
|
||||
ImGui::SameLine();
|
||||
if (ImGui::Button("Shutdown"))
|
||||
if (dropButton("Shutdown"))
|
||||
{
|
||||
std::string params{ " off" };
|
||||
for (std::string& mac : appData.settings.baseStationMacAdresses)
|
||||
@@ -833,30 +814,34 @@ ImVec2 audioDeviceWindow(ApplicationData& appData, std::vector<AudioDevice>& dev
|
||||
|
||||
ImGui::TableNextRow();
|
||||
ImGui::TableNextColumn();
|
||||
float yPosTemp = ImGui::GetCursorPosY();
|
||||
const float yPosOffset = 4.f;
|
||||
|
||||
// Device Name
|
||||
float yPosTemp = ImGui::GetCursorPosY();
|
||||
ImGui::SetCursorPosY(yPosTemp + 4.f);
|
||||
ImGui::SetCursorPosY(yPosTemp + yPosOffset);
|
||||
ImGui::Text(dev.name.c_str());
|
||||
ImGui::SetCursorPosY(yPosTemp);
|
||||
|
||||
// Volume
|
||||
ImGui::TableNextColumn();
|
||||
|
||||
if (dev.state == DEVICE_STATE_ACTIVE)
|
||||
{
|
||||
float startCursorY = ImGui::GetCursorPosY();
|
||||
|
||||
// Mute button
|
||||
ImGui::PushID(std::string("bn_mute_").append(deviceIdUtf8).c_str());
|
||||
ImGui::PushStyleColor(ImGuiCol_Button, ImVec4(0, 0, 0, 0));
|
||||
ImGui::SetCursorPosY(yPosTemp + yPosOffset);
|
||||
|
||||
bool isDeviceMuted = isMuted(dev.volumeInterface);
|
||||
if (ImGui::Button(isDeviceMuted ? ICON_VOLUME_MUTE_FILL : ICON_VOLUME_UP_FILL))
|
||||
if (dropButton(isDeviceMuted ? ICON_VOLUME_MUTE_FILL : ICON_VOLUME_UP_FILL, {}, 2.f, true))
|
||||
{
|
||||
setMuted(dev.volumeInterface, !isDeviceMuted);
|
||||
}
|
||||
|
||||
ImGui::PopStyleColor();
|
||||
ImGui::PopID();
|
||||
ImGui::SameLine(0, 2);
|
||||
ImGui::SameLine();
|
||||
ImGui::SetCursorPosY(startCursorY);
|
||||
|
||||
// Meter
|
||||
static std::array<float, 2> meterValues{};
|
||||
@@ -910,7 +895,7 @@ ImVec2 audioDeviceWindow(ApplicationData& appData, std::vector<AudioDevice>& dev
|
||||
if (dev.isDefaultConsole)
|
||||
{
|
||||
ImGui::SetCursorPosX(ImGui::GetCursorPosX() + getButtonWidth(ICON_MUSIC_2_FILL) / 2.f - circleSize);
|
||||
ImGui::SetCursorPosY(ImGui::GetCursorPosY() + 4.f);
|
||||
ImGui::SetCursorPosY(yPosTemp + yPosOffset);
|
||||
drawCircle(circleSize, IM_COL32(50, 50, 222, 255));
|
||||
}
|
||||
if (customButton("bn_d_", deviceIdUtf8.c_str(), ICON_MUSIC_2_FILL, !dev.isDefaultConsole))
|
||||
@@ -925,7 +910,7 @@ ImVec2 audioDeviceWindow(ApplicationData& appData, std::vector<AudioDevice>& dev
|
||||
if (dev.isDefaultCommunication)
|
||||
{
|
||||
ImGui::SetCursorPosX(ImGui::GetCursorPosX() + getButtonWidth(ICON_PHONE_FILL) / 2.f - circleSize);
|
||||
ImGui::SetCursorPosY(ImGui::GetCursorPosY() + 4.f);
|
||||
ImGui::SetCursorPosY(yPosTemp + yPosOffset);
|
||||
drawCircle(circleSize, IM_COL32(222, 50, 50, 255));
|
||||
}
|
||||
if (customButton("bn_c_", deviceIdUtf8.c_str(), ICON_PHONE_FILL, !dev.isDefaultCommunication))
|
||||
|
||||
@@ -4,11 +4,14 @@
|
||||
#include "ApplicationData.h"
|
||||
|
||||
#include <vector>
|
||||
#include <chrono>
|
||||
|
||||
#define DAY_LINE_WIDTH 3.f
|
||||
#define DAY_LINE_OFFSET 5.f
|
||||
#define DAY_OUTLINE_SIZE 3.f
|
||||
|
||||
typedef std::chrono::time_point<std::chrono::system_clock> TimePoint;
|
||||
|
||||
void init(DrawData& drawData, ApplicationData& customData);
|
||||
void draw(DrawData& drawData, ApplicationData& customData);
|
||||
void cleanup(DrawData& drawData, ApplicationData& appData);
|
||||
|
||||
@@ -56,16 +56,19 @@ void settingsReadLine(ImGuiContext* ctx, ImGuiSettingsHandler* handler, void* en
|
||||
|
||||
std::string task{};
|
||||
task.resize(MAX_TASK_NAME_LENGTH);
|
||||
time_t dayTimestamp;
|
||||
if (sscanf_s(line, "task=%lld %s", &dayTimestamp, &task[0], MAX_TASK_NAME_LENGTH))
|
||||
int year;
|
||||
unsigned int month;
|
||||
unsigned int day;
|
||||
if (sscanf_s(line, "task=%d-%u-%u %s", &year, &month, &day, &task[0], MAX_TASK_NAME_LENGTH))
|
||||
{
|
||||
std::chrono::year_month_day date = std::chrono::year_month_day{ std::chrono::year{year}, std::chrono::month{month}, std::chrono::day{day} };
|
||||
if (settings->tasks.contains(task))
|
||||
{
|
||||
settings->tasks[task].push_back(dayTimestamp);
|
||||
settings->tasks[task].push_back(date);
|
||||
}
|
||||
else
|
||||
{
|
||||
settings->tasks.insert({ task, std::vector{ dayTimestamp } });
|
||||
settings->tasks.insert({ task, std::vector{ date } });
|
||||
}
|
||||
}
|
||||
|
||||
@@ -117,7 +120,7 @@ void settingsWriteAll(ImGuiContext* ctx, ImGuiSettingsHandler* handler, ImGuiTex
|
||||
{
|
||||
for (auto& date : task.second)
|
||||
{
|
||||
outBuf->appendf("task=%lld %s\n", date, task.first.c_str());
|
||||
outBuf->appendf("task=%d-%u-%u %s\n", int{ date.year() }, unsigned int{ date.month() }, unsigned int{ date.day() }, task.first.c_str());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -176,11 +179,14 @@ void setAutostart(bool newValue)
|
||||
void loadUiStyle()
|
||||
{
|
||||
ImGuiStyle& style = ImGui::GetStyle();
|
||||
style.WindowPadding = { 6.f, 8.f };
|
||||
style.WindowPadding = { 6.f, 12.f };
|
||||
style.WindowBorderSize = 0.f;
|
||||
|
||||
style.FramePadding = { 8.f, 4.f };
|
||||
style.ItemSpacing = { 4.f, 4.f };
|
||||
style.WindowRounding = 4.f;
|
||||
|
||||
style.ItemSpacing = { 6.f, 4.f };
|
||||
style.GrabRounding = 2.f;
|
||||
style.PopupBorderSize = 4.f;
|
||||
|
||||
ImVec4* colors = style.Colors;
|
||||
colors[ImGuiCol_Text] = ImVec4(1.00f, 1.00f, 1.00f, 1.00f);
|
||||
@@ -188,7 +194,7 @@ void loadUiStyle()
|
||||
colors[ImGuiCol_WindowBg] = ImVec4(0.10f, 0.07f, 0.09f, 0.99f);
|
||||
colors[ImGuiCol_ChildBg] = ImVec4(0.00f, 0.00f, 0.00f, 0.00f);
|
||||
colors[ImGuiCol_PopupBg] = ImVec4(0.08f, 0.04f, 0.07f, 1.00f);
|
||||
colors[ImGuiCol_Border] = ImVec4(0.43f, 0.43f, 0.50f, 0.50f);
|
||||
colors[ImGuiCol_Border] = ImVec4(0.14f, 0.10f, 0.13f, 0.99f);
|
||||
colors[ImGuiCol_BorderShadow] = ImVec4(0.00f, 0.00f, 0.00f, 0.00f);
|
||||
colors[ImGuiCol_FrameBg] = ImVec4(0.02f, 0.01f, 0.01f, 0.54f);
|
||||
colors[ImGuiCol_FrameBgHovered] = ImVec4(0.98f, 0.36f, 0.36f, 0.40f);
|
||||
@@ -219,7 +225,7 @@ void loadUiStyle()
|
||||
colors[ImGuiCol_Tab] = ImVec4(0.09f, 0.02f, 0.07f, 0.86f);
|
||||
colors[ImGuiCol_TabHovered] = ImVec4(0.28f, 0.15f, 0.24f, 1.00f);
|
||||
colors[ImGuiCol_TabActive] = ImVec4(0.37f, 0.14f, 0.29f, 1.00f);
|
||||
colors[ImGuiCol_TabUnfocused] = ImVec4(0.15f, 0.09f, 0.07f, 0.97f);
|
||||
colors[ImGuiCol_TabUnfocused] = ImVec4(0.33f, 0.21f, 0.28f, 1.00f);
|
||||
colors[ImGuiCol_TabUnfocusedActive] = ImVec4(0.42f, 0.20f, 0.14f, 1.00f);
|
||||
colors[ImGuiCol_PlotLines] = ImVec4(0.61f, 0.61f, 0.61f, 1.00f);
|
||||
colors[ImGuiCol_PlotLinesHovered] = ImVec4(1.00f, 0.43f, 0.35f, 1.00f);
|
||||
|
||||
@@ -1,6 +1,9 @@
|
||||
|
||||
#include "ImguiBase.h"
|
||||
|
||||
// hacky inlcude for custom button alignment
|
||||
#include "imgui_internal.h"
|
||||
|
||||
#include "imgui_impl_glfw.h"
|
||||
#include "imgui_impl_vulkan.h"
|
||||
|
||||
@@ -568,4 +571,88 @@ ImVec2 getWindowSize(GLFWwindow* window)
|
||||
int window_height;
|
||||
glfwGetWindowSize(window, &window_width, &window_height);
|
||||
return ImVec2(window_width, window_height);
|
||||
}
|
||||
}
|
||||
|
||||
void dropShadow()
|
||||
{
|
||||
dropShadow(DEFAULT_DROP_SHADOW_SIZE, ImGui::GetStyle().Colors[DEFAULT_DROP_SHADOW_COLOR_ID]);
|
||||
}
|
||||
|
||||
void dropShadow(const float shadowSize, const ImColor& color)
|
||||
{
|
||||
ImVec2 lastMin = ImGui::GetItemRectMin();
|
||||
ImVec2 lastMax = ImGui::GetItemRectMax();
|
||||
renderDropShadow(shadowSize, lastMin, lastMax, color);
|
||||
}
|
||||
|
||||
void renderDropShadow(const float shadowSize, const ImVec2& min, const ImVec2& max, const ImColor& color)
|
||||
{
|
||||
ImDrawList* windowDrawList = ImGui::GetWindowDrawList();
|
||||
windowDrawList->AddQuadFilled(
|
||||
{ min.x, max.y },
|
||||
{ max.x, max.y },
|
||||
{ max.x + shadowSize, max.y + shadowSize },
|
||||
{ min.x + shadowSize, max.y + shadowSize },
|
||||
color);
|
||||
windowDrawList->AddQuadFilled(
|
||||
{ max.x, min.y },
|
||||
{ max.x + shadowSize, min.y + shadowSize },
|
||||
{ max.x + shadowSize, max.y + shadowSize },
|
||||
{ max.x, max.y },
|
||||
color);
|
||||
}
|
||||
|
||||
bool dropButton(const char* label, const ImVec2& size, float shadowSize, bool smallButton)
|
||||
{
|
||||
ImGuiStyle style = ImGui::GetStyle();
|
||||
ImVec2 backupPadding = style.FramePadding;
|
||||
if (smallButton) style.FramePadding.y = 0.f;
|
||||
|
||||
const ImVec2 labelSize = ImGui::CalcTextSize(label, NULL, true);
|
||||
ImVec2 buttonMin = ImGui::GetCursorScreenPos();
|
||||
|
||||
ImVec2 buttonSize = size;
|
||||
if (buttonSize.x <= 0.f) buttonSize.x = labelSize.x + style.FramePadding.x * 2.0f;
|
||||
if (buttonSize.y <= 0.f) buttonSize.y = labelSize.y + style.FramePadding.y * 2.0f;
|
||||
|
||||
float baseLineOffset = ImGui::GetCurrentWindowRead()->DC.CurrLineTextBaseOffset;
|
||||
if (smallButton && style.FramePadding.y < baseLineOffset) buttonMin.y += baseLineOffset - style.FramePadding.y;
|
||||
|
||||
bool result = ImGui::InvisibleButton(label, buttonSize);
|
||||
bool held = ImGui::IsItemActive();
|
||||
bool hovered = ImGui::IsItemHovered();
|
||||
const ImU32 col = ImGui::GetColorU32((held && hovered) ? ImGuiCol_ButtonActive : hovered ? ImGuiCol_ButtonHovered : ImGuiCol_Button);
|
||||
|
||||
float maxOffset = std::fmaxf(shadowSize - 1.f, 0.f);
|
||||
ImVec2 offset = held ? ImVec2{ maxOffset, maxOffset } : ImVec2{ 0.f, 0.f };
|
||||
ImVec2 rectMin = buttonMin + offset;
|
||||
ImVec2 rectMax = buttonMin + buttonSize + offset;
|
||||
|
||||
ImGui::RenderFrame(rectMin, rectMax, col, true, style.FrameRounding);
|
||||
ImGui::RenderTextClipped(rectMin, rectMax, label, NULL, &labelSize, style.ButtonTextAlign);
|
||||
renderDropShadow(held ? 1.f : shadowSize, rectMin, rectMax, ImGui::GetStyle().Colors[DEFAULT_DROP_SHADOW_COLOR_ID]);
|
||||
|
||||
style.FramePadding = backupPadding;
|
||||
return result;
|
||||
}
|
||||
|
||||
bool checkboxWithDropShadow(const char* label, bool* v, const float shadowSize)
|
||||
{
|
||||
ImGuiStyle& style = ImGui::GetStyle();
|
||||
float oldSpacingX = style.ItemInnerSpacing.x;
|
||||
style.ItemInnerSpacing.x += shadowSize;
|
||||
bool result = ImGui::Checkbox(label, v);
|
||||
style.ItemInnerSpacing.x = oldSpacingX;
|
||||
|
||||
ImVec2 lastMin = ImGui::GetItemRectMin();
|
||||
renderDropShadow(shadowSize, lastMin, lastMin + ImVec2{ ImGui::GetFrameHeight(), ImGui::GetFrameHeight() }, ImGui::GetStyle().Colors[DEFAULT_DROP_SHADOW_COLOR_ID]);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
ImVec2 operator +(const ImVec2& a, const ImVec2& b) { return ImVec2{ a.x + b.x, a.y + b.y }; }
|
||||
ImVec2 operator +(const ImVec2& a, const float s) { return ImVec2{ a.x + s, a.y + s }; }
|
||||
ImVec2 operator -(const ImVec2& a, const ImVec2& b) { return ImVec2{ a.x - b.x, a.y - b.y }; }
|
||||
ImVec2 operator -(const ImVec2& a, const float s) { return ImVec2{ a.x - s, a.y - s }; }
|
||||
ImVec2 operator *(const ImVec2& a, float s) { return ImVec2{ a.x * s, a.y * s }; }
|
||||
ImVec2 operator /(const ImVec2& a, float s) { return ImVec2{ a.x / s, a.y / s }; }
|
||||
|
||||
@@ -57,3 +57,29 @@ public:
|
||||
int startImgui(ImGuiCallbacks& callbacks, const char* title, int windowWidth, int windowHeight);
|
||||
|
||||
ImVec2 getWindowSize(GLFWwindow* window);
|
||||
|
||||
constexpr float DEFAULT_DROP_SHADOW_SIZE = 3.f;
|
||||
constexpr ImGuiCol DEFAULT_DROP_SHADOW_COLOR_ID = ImGuiCol_TabUnfocused;
|
||||
|
||||
void dropShadow();
|
||||
void dropShadow(const float shadowSize, const ImColor& color);
|
||||
void renderDropShadow(const float shadowSize, const ImVec2& min, const ImVec2& max, const ImColor& color);
|
||||
|
||||
bool dropButton(const char* label, const ImVec2& size = ImVec2(0, 0), float shadowSize = DEFAULT_DROP_SHADOW_SIZE, bool smallButton = false);
|
||||
bool checkboxWithDropShadow(const char* label, bool* v, const float shadowSize = DEFAULT_DROP_SHADOW_SIZE);
|
||||
|
||||
template <typename T>
|
||||
float calcInputWidth(const char* formatStr, T value)
|
||||
{
|
||||
constexpr size_t MAX_BUFFER_SIZE = 256;
|
||||
char formatStrBuffer[MAX_BUFFER_SIZE];
|
||||
snprintf(formatStrBuffer, MAX_BUFFER_SIZE, formatStr, value);
|
||||
return ImGui::CalcTextSize(formatStrBuffer).x + ImGui::GetStyle().FramePadding.x * 2.f;
|
||||
}
|
||||
|
||||
ImVec2 operator +(const ImVec2& a, const ImVec2& b);
|
||||
ImVec2 operator +(const ImVec2& a, const float s);
|
||||
ImVec2 operator -(const ImVec2& a, const ImVec2& b);
|
||||
ImVec2 operator -(const ImVec2& a, const float s);
|
||||
ImVec2 operator *(const ImVec2& a, float s);
|
||||
ImVec2 operator /(const ImVec2& a, float s);
|
||||
|
||||
Reference in New Issue
Block a user