yea
This commit is contained in:
@@ -7,6 +7,11 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "ImguiBase", "ImguiBase\Imgu
|
||||
EndProject
|
||||
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "ImguiNodes", "ImguiNodes\ImguiNodes.vcxproj", "{BE4E5CFB-C93F-41D7-B474-721AD43D51A3}"
|
||||
EndProject
|
||||
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "AsuroTool", "AsuroTool\AsuroTool.vcxproj", "{CC10396F-B66E-4240-844F-BEDCDD94E88E}"
|
||||
ProjectSection(ProjectDependencies) = postProject
|
||||
{BB8A1CA3-7660-49E9-BAF1-A99F733F7DB6} = {BB8A1CA3-7660-49E9-BAF1-A99F733F7DB6}
|
||||
EndProjectSection
|
||||
EndProject
|
||||
Global
|
||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||
Debug|x64 = Debug|x64
|
||||
@@ -31,6 +36,14 @@ Global
|
||||
{BE4E5CFB-C93F-41D7-B474-721AD43D51A3}.Release|x64.Build.0 = Release|x64
|
||||
{BE4E5CFB-C93F-41D7-B474-721AD43D51A3}.Release|x86.ActiveCfg = Release|Win32
|
||||
{BE4E5CFB-C93F-41D7-B474-721AD43D51A3}.Release|x86.Build.0 = Release|Win32
|
||||
{CC10396F-B66E-4240-844F-BEDCDD94E88E}.Debug|x64.ActiveCfg = Debug|x64
|
||||
{CC10396F-B66E-4240-844F-BEDCDD94E88E}.Debug|x64.Build.0 = Debug|x64
|
||||
{CC10396F-B66E-4240-844F-BEDCDD94E88E}.Debug|x86.ActiveCfg = Debug|Win32
|
||||
{CC10396F-B66E-4240-844F-BEDCDD94E88E}.Debug|x86.Build.0 = Debug|Win32
|
||||
{CC10396F-B66E-4240-844F-BEDCDD94E88E}.Release|x64.ActiveCfg = Release|x64
|
||||
{CC10396F-B66E-4240-844F-BEDCDD94E88E}.Release|x64.Build.0 = Release|x64
|
||||
{CC10396F-B66E-4240-844F-BEDCDD94E88E}.Release|x86.ActiveCfg = Release|Win32
|
||||
{CC10396F-B66E-4240-844F-BEDCDD94E88E}.Release|x86.Build.0 = Release|Win32
|
||||
EndGlobalSection
|
||||
GlobalSection(SolutionProperties) = preSolution
|
||||
HideSolutionNode = FALSE
|
||||
|
||||
9
AsuroTool/ApplicationData.cpp
Normal file
9
AsuroTool/ApplicationData.cpp
Normal file
@@ -0,0 +1,9 @@
|
||||
#include "ApplicationData.h"
|
||||
|
||||
AudioDevice::~AudioDevice()
|
||||
{
|
||||
if (device)
|
||||
{
|
||||
//device->Release();
|
||||
}
|
||||
}
|
||||
34
AsuroTool/ApplicationData.h
Normal file
34
AsuroTool/ApplicationData.h
Normal file
@@ -0,0 +1,34 @@
|
||||
#pragma once
|
||||
|
||||
#include <mmdeviceapi.h>
|
||||
#include <endpointvolume.h>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
class AudioDevice {
|
||||
public:
|
||||
IMMDevice* device = nullptr;
|
||||
IAudioEndpointVolume* volumeInterface = nullptr;
|
||||
IAudioMeterInformation* meterInterface = nullptr;
|
||||
std::wstring id = {};
|
||||
std::string name = {};
|
||||
unsigned long state = {};
|
||||
bool isDefaultConsole = {};
|
||||
bool isDefaultMedia = {};
|
||||
bool isDefaultCommunication = {};
|
||||
|
||||
~AudioDevice();
|
||||
};
|
||||
|
||||
class ApplicationSettings {
|
||||
public:
|
||||
bool showDisabledDevices = false;
|
||||
bool fitWindowHeight = true;
|
||||
};
|
||||
|
||||
class ApplicationData {
|
||||
public:
|
||||
ApplicationSettings settings = {};
|
||||
std::vector<AudioDevice> playbackDevices = {};
|
||||
std::vector<AudioDevice> recordingDevices = {};
|
||||
};
|
||||
217
AsuroTool/AsuroTool.cpp
Normal file
217
AsuroTool/AsuroTool.cpp
Normal file
@@ -0,0 +1,217 @@
|
||||
//Disables console window
|
||||
#if !_DEBUG
|
||||
#pragma comment(linker, "/SUBSYSTEM:windows /ENTRY:mainCRTStartup")
|
||||
#endif
|
||||
|
||||
#include <windows.h>
|
||||
|
||||
#include <iostream>
|
||||
#include <sstream>
|
||||
|
||||
#include "Util.h"
|
||||
#include "AudioApi.h"
|
||||
#include "resource.h"
|
||||
#include "AsuroTool.h"
|
||||
|
||||
int main()
|
||||
{
|
||||
ApplicationData applicationData{};
|
||||
|
||||
startImgui(&applicationData, init, draw, "Asuro's Tool", 600, 400);
|
||||
}
|
||||
|
||||
void init(DrawData& drawData, void* customData)
|
||||
{
|
||||
ApplicationData* appData = static_cast<ApplicationData*>(customData);
|
||||
|
||||
// Load text font
|
||||
ImGuiIO& io = ImGui::GetIO();
|
||||
io.Fonts->AddFontFromFileTTF("Montserrat-Regular.ttf", 18.0f);
|
||||
|
||||
// Load icon font
|
||||
static const ImWchar icons_ranges[] = { 0xEA01, 0xF2DF, 0 };
|
||||
ImFontConfig icons_config;
|
||||
icons_config.MergeMode = true;
|
||||
icons_config.PixelSnapH = true;
|
||||
io.Fonts->AddFontFromFileTTF("remixicon.ttf", 14.0f, &icons_config, icons_ranges);
|
||||
|
||||
// Set up audio device api
|
||||
HRESULT initResult = CoInitializeEx(NULL, COINIT_MULTITHREADED);
|
||||
isError(initResult, "Failed to initialize COM: ");
|
||||
|
||||
reloadDeviceLists(appData);
|
||||
|
||||
// Set window icon
|
||||
LPWSTR iconId = MAKEINTRESOURCE(IDI_ICON1);
|
||||
HANDLE iconLarge = LoadImageW(GetModuleHandle(NULL), iconId, IMAGE_ICON, 64, 64, 0);
|
||||
HANDLE iconSmall = LoadImageW(GetModuleHandle(NULL), iconId, IMAGE_ICON, 32, 32, 0);
|
||||
SendMessage(drawData.window_handle, WM_SETICON, ICON_BIG, (LPARAM)iconLarge);
|
||||
SendMessage(drawData.window_handle, WM_SETICON, ICON_SMALL, (LPARAM)iconSmall);
|
||||
SendMessage(drawData.window_handle, WM_SETICON, ICON_SMALL2, (LPARAM)iconSmall);
|
||||
}
|
||||
|
||||
void draw(DrawData& drawData, void* customData)
|
||||
{
|
||||
ApplicationData* appData = static_cast<ApplicationData*>(customData);
|
||||
float customYCursor = 0;
|
||||
customYCursor += menuBar(appData).y;
|
||||
|
||||
ImVec2 containingSize = ImGui::GetMainViewport()->Size;
|
||||
|
||||
ImGui::SetNextWindowPos(ImVec2(0, customYCursor));
|
||||
ImGui::SetNextWindowSize(ImVec2(containingSize.x, 0));
|
||||
customYCursor += audioDeviceWindow(appData, appData->playbackDevices, " \xEE\xB8\x84 Playback").y;
|
||||
|
||||
customYCursor += 5.;
|
||||
|
||||
ImGui::SetNextWindowPos(ImVec2(0, customYCursor));
|
||||
ImGui::SetNextWindowSize(ImVec2(containingSize.x, 0));
|
||||
customYCursor += audioDeviceWindow(appData, appData->recordingDevices, " \xEE\xBD\x8F Recording").y;
|
||||
|
||||
if (appData->settings.fitWindowHeight)
|
||||
{
|
||||
drawData.window_size.y = customYCursor;
|
||||
}
|
||||
}
|
||||
|
||||
ImVec2 menuBar(ApplicationData* appData)
|
||||
{
|
||||
ImVec2 size{};
|
||||
|
||||
if (ImGui::BeginMainMenuBar())
|
||||
{
|
||||
if (ImGui::BeginMenu("Settings"))
|
||||
{
|
||||
ImGui::Checkbox("Show Disabled Devices", &appData->settings.showDisabledDevices);
|
||||
ImGui::Checkbox("Fit Window Height", &appData->settings.fitWindowHeight);
|
||||
ImGui::EndMenu();
|
||||
}
|
||||
|
||||
if (ImGui::BeginMenu("Debug"))
|
||||
{
|
||||
if (ImGui::Button("Manual Refresh"))
|
||||
{
|
||||
reloadDeviceLists(appData);
|
||||
}
|
||||
ImGui::EndMenu();
|
||||
}
|
||||
size = ImGui::GetWindowSize();
|
||||
ImGui::EndMainMenuBar();
|
||||
}
|
||||
|
||||
return size;
|
||||
}
|
||||
|
||||
bool customButton(const char* id_start, const char* id_end, const char* title, bool visible)
|
||||
{
|
||||
std::string buttonId(id_start);
|
||||
buttonId.append(id_end);
|
||||
|
||||
bool result = false;
|
||||
if (visible)
|
||||
{
|
||||
ImGui::PushID(buttonId.c_str());
|
||||
result = ImGui::SmallButton(title);
|
||||
ImGui::PopID();
|
||||
}
|
||||
else
|
||||
{
|
||||
ImGui::InvisibleButton(buttonId.c_str(), ImGui::CalcTextSize(title));
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
ImVec2 audioDeviceWindow(ApplicationData* appData, std::vector<AudioDevice>& deviceList, const char* title)
|
||||
{
|
||||
if (ImGui::Begin(title, 0, ImGuiWindowFlags_NoResize))
|
||||
{
|
||||
if (ImGui::BeginTable("DeviceTable", 3, ImGuiTableFlags_Resizable | ImGuiTableFlags_Borders | ImGuiTableFlags_NoSavedSettings))
|
||||
{
|
||||
ImGui::TableSetupColumn("Devices", ImGuiTableColumnFlags_WidthStretch, 3.);
|
||||
ImGui::TableSetupColumn("Volume", ImGuiTableColumnFlags_WidthStretch, 1.);
|
||||
ImGui::TableSetupColumn("Defaults", ImGuiTableColumnFlags_WidthFixed, 55.);
|
||||
ImGui::TableHeadersRow();
|
||||
|
||||
for (auto& dev : deviceList)
|
||||
{
|
||||
std::string deviceIdUtf8 = utf8Encode(dev.id);
|
||||
|
||||
if (dev.state == DEVICE_STATE_ACTIVE)
|
||||
{
|
||||
ImGui::PushStyleColor(ImGuiCol_Text, ImVec4(1., 1., 1., 1.));
|
||||
}
|
||||
else if (!appData->settings.showDisabledDevices)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
else
|
||||
{
|
||||
ImGui::PushStyleColor(ImGuiCol_Text, ImVec4(.7, .7, .7, 1.));
|
||||
}
|
||||
|
||||
ImGui::TableNextRow();
|
||||
ImGui::TableNextColumn();
|
||||
|
||||
ImGui::Text(dev.name.c_str());
|
||||
|
||||
ImGui::TableNextColumn();
|
||||
if (dev.state == DEVICE_STATE_ACTIVE)
|
||||
{
|
||||
float volume = log10f(getMeterValue(dev.meterInterface) * 9. + 1.);
|
||||
|
||||
auto drawList = ImGui::GetWindowDrawList();
|
||||
ImVec2 windowPos = ImGui::GetWindowPos();
|
||||
ImVec2 cursorPos = ImGui::GetCursorScreenPos();
|
||||
ImVec2 space = ImGui::GetContentRegionAvail();
|
||||
float lineY = cursorPos.y + ImGui::GetTextLineHeight() / 2.;
|
||||
|
||||
drawList->AddLine(ImVec2(cursorPos.x, lineY), ImVec2(cursorPos.x + space.x, lineY), IM_COL32(120, 120, 120, 255), 2.);
|
||||
drawList->AddLine(ImVec2(cursorPos.x, lineY), ImVec2(cursorPos.x + space.x * volume, lineY), IM_COL32(200, 200, 255, 255), 3.);
|
||||
}
|
||||
|
||||
ImGui::TableNextColumn();
|
||||
if (dev.state == DEVICE_STATE_ACTIVE)
|
||||
{
|
||||
if (dev.isDefaultConsole)
|
||||
{
|
||||
drawCircle(5, IM_COL32(50, 50, 222, 255));
|
||||
}
|
||||
if (customButton("bn_d_", deviceIdUtf8.c_str(), "\xEE\xBE\x82", !dev.isDefaultConsole))
|
||||
{
|
||||
setDefaultAudioDevice(appData, dev.id.c_str(), ERole::eConsole);
|
||||
}
|
||||
|
||||
ImGui::SameLine();
|
||||
if (dev.isDefaultCommunication)
|
||||
{
|
||||
drawCircle(5, IM_COL32(222, 50, 50, 255));
|
||||
}
|
||||
if (customButton("bn_c_", deviceIdUtf8.c_str(), "\xEE\xBF\xA9", !dev.isDefaultCommunication))
|
||||
{
|
||||
setDefaultAudioDevice(appData, dev.id.c_str(), ERole::eCommunications);
|
||||
}
|
||||
}
|
||||
|
||||
ImGui::PopStyleColor();
|
||||
}
|
||||
|
||||
ImGui::EndTable();
|
||||
}
|
||||
}
|
||||
|
||||
ImVec2 size = ImGui::GetWindowSize();
|
||||
|
||||
ImGui::End();
|
||||
return size;
|
||||
}
|
||||
|
||||
void drawCircle(float radius, ImU32 color)
|
||||
{
|
||||
ImGui::Dummy(ImVec2(0, 0));
|
||||
ImGui::SameLine();
|
||||
auto drawList = ImGui::GetWindowDrawList();
|
||||
ImVec2 cursorPos = ImGui::GetCursorPos();
|
||||
ImVec2 windowPos = ImGui::GetWindowPos();
|
||||
drawList->AddCircleFilled(ImVec2(cursorPos.x + windowPos.x, cursorPos.y + windowPos.y + ImGui::GetTextLineHeight() / 2.), radius, color);
|
||||
}
|
||||
12
AsuroTool/AsuroTool.h
Normal file
12
AsuroTool/AsuroTool.h
Normal file
@@ -0,0 +1,12 @@
|
||||
#pragma once
|
||||
|
||||
#include <vector>
|
||||
|
||||
#include "ImguiBase.h"
|
||||
#include "ApplicationData.h"
|
||||
|
||||
void init(DrawData& drawData, void* customData);
|
||||
void draw(DrawData& drawData, void* customData);
|
||||
ImVec2 menuBar(ApplicationData* appData);
|
||||
ImVec2 audioDeviceWindow(ApplicationData* appData, std::vector<AudioDevice>& deviceList, const char* title);
|
||||
void drawCircle(float radius, ImU32 color);
|
||||
81
AsuroTool/AsuroTool.rc
Normal file
81
AsuroTool/AsuroTool.rc
Normal file
@@ -0,0 +1,81 @@
|
||||
// Microsoft Visual C++ generated resource script.
|
||||
//
|
||||
#include "resource.h"
|
||||
|
||||
#define APSTUDIO_READONLY_SYMBOLS
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Generated from the TEXTINCLUDE 2 resource.
|
||||
//
|
||||
#include "winres.h"
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
#undef APSTUDIO_READONLY_SYMBOLS
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
// English (United States) resources
|
||||
|
||||
#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU)
|
||||
LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US
|
||||
#pragma code_page(1252)
|
||||
|
||||
#ifdef APSTUDIO_INVOKED
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// TEXTINCLUDE
|
||||
//
|
||||
|
||||
1 TEXTINCLUDE
|
||||
BEGIN
|
||||
"resource.h\0"
|
||||
END
|
||||
|
||||
2 TEXTINCLUDE
|
||||
BEGIN
|
||||
"#include ""winres.h""\r\n"
|
||||
"\0"
|
||||
END
|
||||
|
||||
3 TEXTINCLUDE
|
||||
BEGIN
|
||||
"\r\n"
|
||||
"\0"
|
||||
END
|
||||
|
||||
#endif // APSTUDIO_INVOKED
|
||||
|
||||
#endif // English (United States) resources
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
// English (United Kingdom) resources
|
||||
|
||||
#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENG)
|
||||
LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_UK
|
||||
#pragma code_page(1252)
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Icon
|
||||
//
|
||||
|
||||
// Icon with lowest ID value placed first to ensure application icon
|
||||
// remains consistent on all systems.
|
||||
IDI_ICON1 ICON "kaiju.ico"
|
||||
|
||||
#endif // English (United Kingdom) resources
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
|
||||
|
||||
#ifndef APSTUDIO_INVOKED
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Generated from the TEXTINCLUDE 3 resource.
|
||||
//
|
||||
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
#endif // not APSTUDIO_INVOKED
|
||||
|
||||
202
AsuroTool/AsuroTool.vcxproj
Normal file
202
AsuroTool/AsuroTool.vcxproj
Normal file
@@ -0,0 +1,202 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<ItemGroup Label="ProjectConfigurations">
|
||||
<ProjectConfiguration Include="Debug|Win32">
|
||||
<Configuration>Debug</Configuration>
|
||||
<Platform>Win32</Platform>
|
||||
</ProjectConfiguration>
|
||||
<ProjectConfiguration Include="Release|Win32">
|
||||
<Configuration>Release</Configuration>
|
||||
<Platform>Win32</Platform>
|
||||
</ProjectConfiguration>
|
||||
<ProjectConfiguration Include="Debug|x64">
|
||||
<Configuration>Debug</Configuration>
|
||||
<Platform>x64</Platform>
|
||||
</ProjectConfiguration>
|
||||
<ProjectConfiguration Include="Release|x64">
|
||||
<Configuration>Release</Configuration>
|
||||
<Platform>x64</Platform>
|
||||
</ProjectConfiguration>
|
||||
</ItemGroup>
|
||||
<PropertyGroup Label="Globals">
|
||||
<VCProjectVersion>16.0</VCProjectVersion>
|
||||
<Keyword>Win32Proj</Keyword>
|
||||
<ProjectGuid>{cc10396f-b66e-4240-844f-bedcdd94e88e}</ProjectGuid>
|
||||
<RootNamespace>AsuroTool</RootNamespace>
|
||||
<WindowsTargetPlatformVersion>10.0</WindowsTargetPlatformVersion>
|
||||
</PropertyGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
|
||||
<ConfigurationType>Application</ConfigurationType>
|
||||
<UseDebugLibraries>true</UseDebugLibraries>
|
||||
<PlatformToolset>v143</PlatformToolset>
|
||||
<CharacterSet>Unicode</CharacterSet>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
|
||||
<ConfigurationType>Application</ConfigurationType>
|
||||
<UseDebugLibraries>false</UseDebugLibraries>
|
||||
<PlatformToolset>v143</PlatformToolset>
|
||||
<WholeProgramOptimization>true</WholeProgramOptimization>
|
||||
<CharacterSet>Unicode</CharacterSet>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
|
||||
<ConfigurationType>Application</ConfigurationType>
|
||||
<UseDebugLibraries>true</UseDebugLibraries>
|
||||
<PlatformToolset>v143</PlatformToolset>
|
||||
<CharacterSet>Unicode</CharacterSet>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
|
||||
<ConfigurationType>Application</ConfigurationType>
|
||||
<UseDebugLibraries>false</UseDebugLibraries>
|
||||
<PlatformToolset>v143</PlatformToolset>
|
||||
<WholeProgramOptimization>true</WholeProgramOptimization>
|
||||
<CharacterSet>Unicode</CharacterSet>
|
||||
</PropertyGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
|
||||
<ImportGroup Label="ExtensionSettings">
|
||||
</ImportGroup>
|
||||
<ImportGroup Label="Shared">
|
||||
</ImportGroup>
|
||||
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
|
||||
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||
</ImportGroup>
|
||||
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
|
||||
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||
</ImportGroup>
|
||||
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
|
||||
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||
</ImportGroup>
|
||||
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
|
||||
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||
</ImportGroup>
|
||||
<PropertyGroup Label="UserMacros" />
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
|
||||
<LinkIncremental>true</LinkIncremental>
|
||||
<IncludePath>E:\Code\AsuroImgui\ImguiBase;$(VC_IncludePath);$(WindowsSDK_IncludePath);</IncludePath>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
|
||||
<LinkIncremental>false</LinkIncremental>
|
||||
<IncludePath>E:\Code\AsuroImgui\ImguiBase;$(VC_IncludePath);$(WindowsSDK_IncludePath);</IncludePath>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
|
||||
<LinkIncremental>true</LinkIncremental>
|
||||
<IncludePath>E:\Code\AsuroImgui\ImguiBase;$(VC_IncludePath);$(WindowsSDK_IncludePath);</IncludePath>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
|
||||
<LinkIncremental>false</LinkIncremental>
|
||||
<IncludePath>E:\Code\AsuroImgui\ImguiBase;$(VC_IncludePath);$(WindowsSDK_IncludePath);</IncludePath>
|
||||
</PropertyGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
|
||||
<ClCompile>
|
||||
<WarningLevel>Level3</WarningLevel>
|
||||
<SDLCheck>true</SDLCheck>
|
||||
<PreprocessorDefinitions>WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<ConformanceMode>true</ConformanceMode>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<SubSystem>Console</SubSystem>
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
|
||||
<ClCompile>
|
||||
<WarningLevel>Level3</WarningLevel>
|
||||
<FunctionLevelLinking>true</FunctionLevelLinking>
|
||||
<IntrinsicFunctions>true</IntrinsicFunctions>
|
||||
<SDLCheck>true</SDLCheck>
|
||||
<PreprocessorDefinitions>WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<ConformanceMode>true</ConformanceMode>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<SubSystem>Console</SubSystem>
|
||||
<EnableCOMDATFolding>true</EnableCOMDATFolding>
|
||||
<OptimizeReferences>true</OptimizeReferences>
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
|
||||
<ClCompile>
|
||||
<WarningLevel>Level3</WarningLevel>
|
||||
<SDLCheck>true</SDLCheck>
|
||||
<PreprocessorDefinitions>_DEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<ConformanceMode>true</ConformanceMode>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<SubSystem>Console</SubSystem>
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
|
||||
<ClCompile>
|
||||
<WarningLevel>Level3</WarningLevel>
|
||||
<FunctionLevelLinking>true</FunctionLevelLinking>
|
||||
<IntrinsicFunctions>true</IntrinsicFunctions>
|
||||
<SDLCheck>true</SDLCheck>
|
||||
<PreprocessorDefinitions>NDEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<ConformanceMode>true</ConformanceMode>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<SubSystem>Console</SubSystem>
|
||||
<EnableCOMDATFolding>true</EnableCOMDATFolding>
|
||||
<OptimizeReferences>true</OptimizeReferences>
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemGroup>
|
||||
<ClCompile Include="ApplicationData.cpp" />
|
||||
<ClCompile Include="AsuroTool.cpp" />
|
||||
<ClCompile Include="Util.cpp" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="ApplicationData.h" />
|
||||
<ClInclude Include="AsuroTool.h" />
|
||||
<ClCompile Include="AudioApi.cpp" />
|
||||
<ClInclude Include="AudioApi.h" />
|
||||
<ClInclude Include="PolicyConfig.h" />
|
||||
<ClInclude Include="resource.h" />
|
||||
<ClInclude Include="Util.h" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\ImguiBase\ImguiBase.vcxproj">
|
||||
<Project>{bb8a1ca3-7660-49e9-baf1-a99f733f7db6}</Project>
|
||||
</ProjectReference>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<CopyFileToFolders Include="Montserrat-Regular.ttf">
|
||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">false</ExcludedFromBuild>
|
||||
<DeploymentContent Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</DeploymentContent>
|
||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">false</ExcludedFromBuild>
|
||||
<DeploymentContent Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">true</DeploymentContent>
|
||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">false</ExcludedFromBuild>
|
||||
<DeploymentContent Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">true</DeploymentContent>
|
||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|x64'">false</ExcludedFromBuild>
|
||||
<DeploymentContent Condition="'$(Configuration)|$(Platform)'=='Release|x64'">true</DeploymentContent>
|
||||
<FileType>Document</FileType>
|
||||
</CopyFileToFolders>
|
||||
<CopyFileToFolders Include="remixicon.ttf">
|
||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">false</ExcludedFromBuild>
|
||||
<DeploymentContent Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</DeploymentContent>
|
||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">false</ExcludedFromBuild>
|
||||
<DeploymentContent Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">true</DeploymentContent>
|
||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">false</ExcludedFromBuild>
|
||||
<DeploymentContent Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">true</DeploymentContent>
|
||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|x64'">false</ExcludedFromBuild>
|
||||
<DeploymentContent Condition="'$(Configuration)|$(Platform)'=='Release|x64'">true</DeploymentContent>
|
||||
<FileType>Document</FileType>
|
||||
</CopyFileToFolders>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ResourceCompile Include="AsuroTool.rc" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Image Include="d:\nextcloud\dragon collection\profile pics\icon2.ico" />
|
||||
<Image Include="d:\nextcloud\dragon collection\profile pics\icon3.ico" />
|
||||
<Image Include="D:\Nextcloud\Dragon Collection\Profile Pics\kaiju.ico" />
|
||||
<Image Include="kaiju.ico" />
|
||||
<Image Include="kaiju32.png" />
|
||||
<Image Include="kaiju64.png" />
|
||||
</ItemGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
|
||||
<ImportGroup Label="ExtensionTargets">
|
||||
</ImportGroup>
|
||||
</Project>
|
||||
84
AsuroTool/AsuroTool.vcxproj.filters
Normal file
84
AsuroTool/AsuroTool.vcxproj.filters
Normal file
@@ -0,0 +1,84 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<ItemGroup>
|
||||
<Filter Include="Source Files">
|
||||
<UniqueIdentifier>{4FC737F1-C7A5-4376-A066-2A32D752A2FF}</UniqueIdentifier>
|
||||
<Extensions>cpp;c;cc;cxx;c++;cppm;ixx;def;odl;idl;hpj;bat;asm;asmx</Extensions>
|
||||
</Filter>
|
||||
<Filter Include="Header Files">
|
||||
<UniqueIdentifier>{93995380-89BD-4b04-88EB-625FBE52EBFB}</UniqueIdentifier>
|
||||
<Extensions>h;hh;hpp;hxx;h++;hm;inl;inc;ipp;xsd</Extensions>
|
||||
</Filter>
|
||||
<Filter Include="Resource Files">
|
||||
<UniqueIdentifier>{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}</UniqueIdentifier>
|
||||
<Extensions>rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms</Extensions>
|
||||
</Filter>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClCompile Include="AsuroTool.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="AudioApi.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="Util.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="ApplicationData.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="AsuroTool.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="Util.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="PolicyConfig.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="AudioApi.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="ApplicationData.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="resource.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<CopyFileToFolders Include="Montserrat-Regular.ttf">
|
||||
<Filter>Resource Files</Filter>
|
||||
</CopyFileToFolders>
|
||||
<CopyFileToFolders Include="remixicon.ttf">
|
||||
<Filter>Resource Files</Filter>
|
||||
</CopyFileToFolders>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ResourceCompile Include="AsuroTool.rc">
|
||||
<Filter>Resource Files</Filter>
|
||||
</ResourceCompile>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Image Include="d:\nextcloud\dragon collection\profile pics\icon2.ico">
|
||||
<Filter>Resource Files</Filter>
|
||||
</Image>
|
||||
<Image Include="kaiju64.png">
|
||||
<Filter>Resource Files</Filter>
|
||||
</Image>
|
||||
<Image Include="d:\nextcloud\dragon collection\profile pics\icon3.ico">
|
||||
<Filter>Resource Files</Filter>
|
||||
</Image>
|
||||
<Image Include="D:\Nextcloud\Dragon Collection\Profile Pics\kaiju.ico">
|
||||
<Filter>Resource Files</Filter>
|
||||
</Image>
|
||||
<Image Include="kaiju32.png">
|
||||
<Filter>Resource Files</Filter>
|
||||
</Image>
|
||||
<Image Include="kaiju.ico">
|
||||
<Filter>Resource Files</Filter>
|
||||
</Image>
|
||||
</ItemGroup>
|
||||
</Project>
|
||||
172
AsuroTool/AudioApi.cpp
Normal file
172
AsuroTool/AudioApi.cpp
Normal file
@@ -0,0 +1,172 @@
|
||||
|
||||
#include <windows.h>
|
||||
#include <functiondiscoverykeys.h>
|
||||
#include <endpointvolume.h>
|
||||
|
||||
#include <vector>
|
||||
#include <algorithm>
|
||||
|
||||
#include "ImguiBase.h"
|
||||
#include "Util.h"
|
||||
#include "AudioApi.h"
|
||||
#include "PolicyConfig.h"
|
||||
|
||||
HRESULT getDeviceProperty(IPropertyStore* propertyStore, const PROPERTYKEY propertyKey, PROPVARIANT* outData)
|
||||
{
|
||||
PropVariantInit(outData);
|
||||
HRESULT nameResult = propertyStore->GetValue(propertyKey, outData);
|
||||
return nameResult;
|
||||
}
|
||||
|
||||
HRESULT getDevicePropertyString(IPropertyStore* propertyStore, const PROPERTYKEY propertyKey, PROPVARIANT* outData, const wchar_t*& outString, const wchar_t* defaultStr)
|
||||
{
|
||||
HRESULT result = getDeviceProperty(propertyStore, propertyKey, outData);
|
||||
outString = outData->vt != VT_LPWSTR ? defaultStr : outData->pwszVal;
|
||||
return result;
|
||||
}
|
||||
|
||||
void setDefaultAudioDevice(ApplicationData* appData, const wchar_t* deviceId, ERole role)
|
||||
{
|
||||
IPolicyConfigVista* pPolicyConfig;
|
||||
|
||||
HRESULT hr = CoCreateInstance(__uuidof(CPolicyConfigVistaClient), NULL, CLSCTX_ALL, __uuidof(IPolicyConfigVista), (LPVOID*)&pPolicyConfig);
|
||||
if (!isError(hr, "Failed to set default audio device: "))
|
||||
{
|
||||
hr = pPolicyConfig->SetDefaultEndpoint(deviceId, role);
|
||||
pPolicyConfig->Release();
|
||||
reloadDeviceLists(appData);
|
||||
}
|
||||
}
|
||||
|
||||
void loadAudioDevices(std::vector<AudioDevice>& deviceList, EDataFlow deviceType)
|
||||
{
|
||||
deviceList.clear();
|
||||
|
||||
HRESULT err;
|
||||
IMMDeviceEnumerator* deviceEnumerator = NULL;
|
||||
IMMDeviceCollection* deviceCollection = NULL;
|
||||
|
||||
err = CoCreateInstance(__uuidof(MMDeviceEnumerator), NULL, CLSCTX_INPROC_SERVER, IID_PPV_ARGS(&deviceEnumerator));
|
||||
if (isError(err, "Failed to set up audio device enumerator: ")) return;
|
||||
|
||||
err = deviceEnumerator->EnumAudioEndpoints(deviceType, DEVICE_STATE_ACTIVE | DEVICE_STATE_DISABLED, &deviceCollection);
|
||||
if (isError(err, "Failed to enumerate audio devices: ")) return;
|
||||
|
||||
UINT deviceCount;
|
||||
err = deviceCollection->GetCount(&deviceCount);
|
||||
if (isError(err, "Failed to count audio devices: ")) return;
|
||||
|
||||
IMMDevice* defaultConsoleDevice = NULL;
|
||||
LPWSTR defaultConsoleId = nullptr;
|
||||
err = deviceEnumerator->GetDefaultAudioEndpoint(deviceType, ERole::eConsole, &defaultConsoleDevice);
|
||||
if (!FAILED(err))
|
||||
{
|
||||
defaultConsoleDevice->GetId(&defaultConsoleId);
|
||||
}
|
||||
|
||||
IMMDevice* defaultMediaOutput = NULL;
|
||||
LPWSTR defaultMediaId = nullptr;
|
||||
err = deviceEnumerator->GetDefaultAudioEndpoint(deviceType, ERole::eMultimedia, &defaultMediaOutput);
|
||||
if (!FAILED(err))
|
||||
{
|
||||
defaultMediaOutput->GetId(&defaultMediaId);
|
||||
}
|
||||
|
||||
IMMDevice* defaultCommunicationOutput = NULL;
|
||||
LPWSTR defaultCommunicationId = nullptr;
|
||||
err = deviceEnumerator->GetDefaultAudioEndpoint(deviceType, ERole::eCommunications, &defaultCommunicationOutput);
|
||||
if (!FAILED(err))
|
||||
{
|
||||
defaultCommunicationOutput->GetId(&defaultCommunicationId);
|
||||
}
|
||||
|
||||
for (UINT i = 0; i < deviceCount; i += 1)
|
||||
{
|
||||
IMMDevice* device;
|
||||
err = deviceCollection->Item(i, &device);
|
||||
isError(err, std::stringstream("Failed to get device ") << i << ": ");
|
||||
|
||||
LPWSTR deviceId;
|
||||
err = device->GetId(&deviceId);
|
||||
isError(err, std::stringstream("Failed to get device id ") << i << ": ");
|
||||
|
||||
IPropertyStore* propertyStore;
|
||||
err = device->OpenPropertyStore(STGM_READ, &propertyStore);
|
||||
isError(err, std::stringstream("Failed to open device ") << i << "prop store: ");
|
||||
|
||||
PROPVARIANT deviceNameProp;
|
||||
const wchar_t* deviceName;
|
||||
err = getDevicePropertyString(propertyStore, PKEY_Device_FriendlyName, &deviceNameProp, deviceName);
|
||||
isError(err, std::stringstream("Failed to read name of device ") << i << ": ");
|
||||
|
||||
DWORD deviceState;
|
||||
err = device->GetState(&deviceState);
|
||||
isError(err, std::stringstream("Failed to reat state of device ") << i << ": ");
|
||||
|
||||
IAudioEndpointVolume* volumeInterface;
|
||||
err = device->Activate(__uuidof(IAudioEndpointVolume), CLSCTX_INPROC_SERVER, NULL, (LPVOID*)&volumeInterface);
|
||||
isError(err, "Failed to get audio endpoint volume interface: ");
|
||||
|
||||
IAudioMeterInformation* meterInterface;
|
||||
err = device->Activate(__uuidof(IAudioMeterInformation), CLSCTX_INPROC_SERVER, NULL, (LPVOID*)&meterInterface);
|
||||
isError(err, "Failed to get audio meter interface: ");
|
||||
|
||||
deviceList.push_back({
|
||||
device,
|
||||
volumeInterface,
|
||||
meterInterface,
|
||||
std::wstring(deviceId),
|
||||
utf8Encode(deviceName),
|
||||
deviceState,
|
||||
utf8Encode(defaultConsoleId) == utf8Encode(deviceId),
|
||||
utf8Encode(defaultMediaId) == utf8Encode(deviceId),
|
||||
utf8Encode(defaultCommunicationId) == utf8Encode(deviceId),
|
||||
});
|
||||
|
||||
// Free stuff
|
||||
if (propertyStore)
|
||||
{
|
||||
propertyStore->Release();
|
||||
}
|
||||
CoTaskMemFree(deviceId);
|
||||
}
|
||||
|
||||
if (deviceEnumerator)
|
||||
{
|
||||
deviceEnumerator->Release();
|
||||
}
|
||||
if (deviceCollection)
|
||||
{
|
||||
deviceCollection->Release();
|
||||
}
|
||||
|
||||
std::sort(deviceList.begin(), deviceList.end(), [](AudioDevice& a, AudioDevice& b) { return a.state < b.state; });
|
||||
}
|
||||
|
||||
void reloadDeviceLists(ApplicationData* appData)
|
||||
{
|
||||
loadAudioDevices(appData->playbackDevices, EDataFlow::eRender);
|
||||
loadAudioDevices(appData->recordingDevices, EDataFlow::eCapture);
|
||||
}
|
||||
|
||||
float getVolume(IAudioEndpointVolume* volumeInterface)
|
||||
{
|
||||
float volume;
|
||||
if (FAILED(volumeInterface->GetChannelVolumeLevel(0, &volume)))
|
||||
{
|
||||
volume = 0.;
|
||||
}
|
||||
|
||||
return volume;
|
||||
}
|
||||
|
||||
float getMeterValue(IAudioMeterInformation* meterInterface)
|
||||
{
|
||||
float volume;
|
||||
if (FAILED(meterInterface->GetPeakValue(&volume)))
|
||||
{
|
||||
volume = 0.;
|
||||
}
|
||||
|
||||
return volume;
|
||||
}
|
||||
13
AsuroTool/AudioApi.h
Normal file
13
AsuroTool/AudioApi.h
Normal file
@@ -0,0 +1,13 @@
|
||||
#pragma once
|
||||
|
||||
#include <mmdeviceapi.h>
|
||||
|
||||
#include "ApplicationData.h"
|
||||
|
||||
HRESULT getDeviceProperty(IPropertyStore* propertyStore, const PROPERTYKEY propertyKey, PROPVARIANT* outData);
|
||||
HRESULT getDevicePropertyString(IPropertyStore* propertyStore, const PROPERTYKEY propertyKey, PROPVARIANT* outData, const wchar_t*& outString, const wchar_t* defaultStr = L"Unknown");
|
||||
void setDefaultAudioDevice(ApplicationData* appData, const wchar_t* deviceId, ERole role);
|
||||
void loadAudioDevices(std::vector<AudioDevice>& deviceList, EDataFlow deviceType);
|
||||
void reloadDeviceLists(ApplicationData* appData);
|
||||
float getVolume(IAudioEndpointVolume* volumeInterface);
|
||||
float getMeterValue(IAudioMeterInformation* meterInterface);
|
||||
BIN
AsuroTool/Montserrat-Regular.ttf
Normal file
BIN
AsuroTool/Montserrat-Regular.ttf
Normal file
Binary file not shown.
201
AsuroTool/PolicyConfig.h
Normal file
201
AsuroTool/PolicyConfig.h
Normal file
@@ -0,0 +1,201 @@
|
||||
/* The MIT License (MIT)
|
||||
|
||||
Copyright (c) 2015 DefSound
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
*/
|
||||
// ----------------------------------------------------------------------------
|
||||
// PolicyConfig.h
|
||||
// Undocumented COM-interface IPolicyConfig.
|
||||
// Use for set default audio render endpoint
|
||||
// @author EreTIk
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
|
||||
#pragma once
|
||||
#include "mmreg.h"
|
||||
|
||||
|
||||
interface DECLSPEC_UUID("f8679f50-850a-41cf-9c72-430f290290c8") IPolicyConfig;
|
||||
class DECLSPEC_UUID("870af99c-171d-4f9e-af0d-e63df40c2bc9") CPolicyConfigClient;
|
||||
// ----------------------------------------------------------------------------
|
||||
// class CPolicyConfigClient
|
||||
// {870af99c-171d-4f9e-af0d-e63df40c2bc9}
|
||||
//
|
||||
// interface IPolicyConfig
|
||||
// {f8679f50-850a-41cf-9c72-430f290290c8}
|
||||
//
|
||||
// Query interface:
|
||||
// CComPtr<IPolicyConfig> PolicyConfig;
|
||||
// PolicyConfig.CoCreateInstance(__uuidof(CPolicyConfigClient));
|
||||
//
|
||||
// @compatible: Windows 7 and Later
|
||||
// ----------------------------------------------------------------------------
|
||||
interface IPolicyConfig : public IUnknown
|
||||
{
|
||||
public:
|
||||
|
||||
virtual HRESULT GetMixFormat(
|
||||
PCWSTR,
|
||||
WAVEFORMATEX **
|
||||
);
|
||||
|
||||
virtual HRESULT STDMETHODCALLTYPE GetDeviceFormat(
|
||||
PCWSTR,
|
||||
INT,
|
||||
WAVEFORMATEX **
|
||||
);
|
||||
|
||||
virtual HRESULT STDMETHODCALLTYPE ResetDeviceFormat(
|
||||
PCWSTR
|
||||
);
|
||||
|
||||
virtual HRESULT STDMETHODCALLTYPE SetDeviceFormat(
|
||||
PCWSTR,
|
||||
WAVEFORMATEX *,
|
||||
WAVEFORMATEX *
|
||||
);
|
||||
|
||||
virtual HRESULT STDMETHODCALLTYPE GetProcessingPeriod(
|
||||
PCWSTR,
|
||||
INT,
|
||||
PINT64,
|
||||
PINT64
|
||||
);
|
||||
|
||||
virtual HRESULT STDMETHODCALLTYPE SetProcessingPeriod(
|
||||
PCWSTR,
|
||||
PINT64
|
||||
);
|
||||
|
||||
virtual HRESULT STDMETHODCALLTYPE GetShareMode(
|
||||
PCWSTR,
|
||||
struct DeviceShareMode *
|
||||
);
|
||||
|
||||
virtual HRESULT STDMETHODCALLTYPE SetShareMode(
|
||||
PCWSTR,
|
||||
struct DeviceShareMode *
|
||||
);
|
||||
|
||||
virtual HRESULT STDMETHODCALLTYPE GetPropertyValue(
|
||||
PCWSTR,
|
||||
const PROPERTYKEY &,
|
||||
PROPVARIANT *
|
||||
);
|
||||
|
||||
virtual HRESULT STDMETHODCALLTYPE SetPropertyValue(
|
||||
PCWSTR,
|
||||
const PROPERTYKEY &,
|
||||
PROPVARIANT *
|
||||
);
|
||||
|
||||
virtual HRESULT STDMETHODCALLTYPE SetDefaultEndpoint(
|
||||
__in PCWSTR wszDeviceId,
|
||||
__in ERole eRole
|
||||
);
|
||||
|
||||
virtual HRESULT STDMETHODCALLTYPE SetEndpointVisibility(
|
||||
PCWSTR,
|
||||
INT
|
||||
);
|
||||
};
|
||||
|
||||
interface DECLSPEC_UUID("568b9108-44bf-40b4-9006-86afe5b5a620") IPolicyConfigVista;
|
||||
class DECLSPEC_UUID("294935CE-F637-4E7C-A41B-AB255460B862") CPolicyConfigVistaClient;
|
||||
// ----------------------------------------------------------------------------
|
||||
// class CPolicyConfigVistaClient
|
||||
// {294935CE-F637-4E7C-A41B-AB255460B862}
|
||||
//
|
||||
// interface IPolicyConfigVista
|
||||
// {568b9108-44bf-40b4-9006-86afe5b5a620}
|
||||
//
|
||||
// Query interface:
|
||||
// CComPtr<IPolicyConfigVista> PolicyConfig;
|
||||
// PolicyConfig.CoCreateInstance(__uuidof(CPolicyConfigVistaClient));
|
||||
//
|
||||
// @compatible: Windows Vista and Later
|
||||
// ----------------------------------------------------------------------------
|
||||
interface IPolicyConfigVista : public IUnknown
|
||||
{
|
||||
public:
|
||||
|
||||
virtual HRESULT GetMixFormat(
|
||||
PCWSTR,
|
||||
WAVEFORMATEX **
|
||||
); // not available on Windows 7, use method from IPolicyConfig
|
||||
|
||||
virtual HRESULT STDMETHODCALLTYPE GetDeviceFormat(
|
||||
PCWSTR,
|
||||
INT,
|
||||
WAVEFORMATEX **
|
||||
);
|
||||
|
||||
virtual HRESULT STDMETHODCALLTYPE SetDeviceFormat(
|
||||
PCWSTR,
|
||||
WAVEFORMATEX *,
|
||||
WAVEFORMATEX *
|
||||
);
|
||||
|
||||
virtual HRESULT STDMETHODCALLTYPE GetProcessingPeriod(
|
||||
PCWSTR,
|
||||
INT,
|
||||
PINT64,
|
||||
PINT64
|
||||
); // not available on Windows 7, use method from IPolicyConfig
|
||||
|
||||
virtual HRESULT STDMETHODCALLTYPE SetProcessingPeriod(
|
||||
PCWSTR,
|
||||
PINT64
|
||||
); // not available on Windows 7, use method from IPolicyConfig
|
||||
|
||||
virtual HRESULT STDMETHODCALLTYPE GetShareMode(
|
||||
PCWSTR,
|
||||
struct DeviceShareMode *
|
||||
); // not available on Windows 7, use method from IPolicyConfig
|
||||
|
||||
virtual HRESULT STDMETHODCALLTYPE SetShareMode(
|
||||
PCWSTR,
|
||||
struct DeviceShareMode *
|
||||
); // not available on Windows 7, use method from IPolicyConfig
|
||||
|
||||
virtual HRESULT STDMETHODCALLTYPE GetPropertyValue(
|
||||
PCWSTR,
|
||||
const PROPERTYKEY &,
|
||||
PROPVARIANT *
|
||||
);
|
||||
|
||||
virtual HRESULT STDMETHODCALLTYPE SetPropertyValue(
|
||||
PCWSTR,
|
||||
const PROPERTYKEY &,
|
||||
PROPVARIANT *
|
||||
);
|
||||
|
||||
virtual HRESULT STDMETHODCALLTYPE SetDefaultEndpoint(
|
||||
__in PCWSTR wszDeviceId,
|
||||
__in ERole eRole
|
||||
);
|
||||
|
||||
virtual HRESULT STDMETHODCALLTYPE SetEndpointVisibility(
|
||||
PCWSTR,
|
||||
INT
|
||||
); // not available on Windows 7, use method from IPolicyConfig
|
||||
};
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
31
AsuroTool/Util.cpp
Normal file
31
AsuroTool/Util.cpp
Normal file
@@ -0,0 +1,31 @@
|
||||
#include <iostream>
|
||||
|
||||
#include "Util.h"
|
||||
|
||||
bool isError(const HRESULT result, const std::stringstream message)
|
||||
{
|
||||
if (FAILED(result))
|
||||
{
|
||||
std::cout << message.str() << std::hex << result << std::endl;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool isError(const HRESULT result, const char* message)
|
||||
{
|
||||
return isError(result, std::stringstream(message));
|
||||
}
|
||||
|
||||
std::string utf8Encode(const std::wstring& wstr)
|
||||
{
|
||||
if (wstr.empty())
|
||||
{
|
||||
return std::string();
|
||||
}
|
||||
|
||||
int sizeNeeded = WideCharToMultiByte(CP_UTF8, 0, wstr.c_str(), -1, NULL, 0, NULL, NULL);
|
||||
std::string resultString(sizeNeeded, 0);
|
||||
WideCharToMultiByte(CP_UTF8, 0, wstr.c_str(), -1, &resultString[0], sizeNeeded, NULL, NULL);
|
||||
return resultString;
|
||||
}
|
||||
8
AsuroTool/Util.h
Normal file
8
AsuroTool/Util.h
Normal file
@@ -0,0 +1,8 @@
|
||||
#pragma once
|
||||
|
||||
#include <windows.h>
|
||||
#include <sstream>
|
||||
|
||||
bool isError(const HRESULT result, const std::stringstream message);
|
||||
bool isError(const HRESULT result, const char* message);
|
||||
std::string utf8Encode(const std::wstring& wstr);
|
||||
BIN
AsuroTool/kaiju.ico
Normal file
BIN
AsuroTool/kaiju.ico
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 360 KiB |
BIN
AsuroTool/remixicon.ttf
Normal file
BIN
AsuroTool/remixicon.ttf
Normal file
Binary file not shown.
16
AsuroTool/resource.h
Normal file
16
AsuroTool/resource.h
Normal file
@@ -0,0 +1,16 @@
|
||||
//{{NO_DEPENDENCIES}}
|
||||
// Microsoft Visual C++ generated include file.
|
||||
// Used by AsuroTool.rc
|
||||
//
|
||||
#define IDI_ICON1 109
|
||||
|
||||
// Next default values for new objects
|
||||
//
|
||||
#ifdef APSTUDIO_INVOKED
|
||||
#ifndef APSTUDIO_READONLY_SYMBOLS
|
||||
#define _APS_NEXT_RESOURCE_VALUE 112
|
||||
#define _APS_NEXT_COMMAND_VALUE 40001
|
||||
#define _APS_NEXT_CONTROL_VALUE 1001
|
||||
#define _APS_NEXT_SYMED_VALUE 101
|
||||
#endif
|
||||
#endif
|
||||
@@ -5,7 +5,9 @@
|
||||
#include <iostream>
|
||||
#define GLFW_INCLUDE_NONE
|
||||
#define GLFW_INCLUDE_VULKAN
|
||||
#define GLFW_EXPOSE_NATIVE_WIN32
|
||||
#include <GLFW/glfw3.h>
|
||||
#include <GLFW/glfw3native.h>
|
||||
#include <vulkan/vulkan.h>
|
||||
|
||||
static VkAllocationCallbacks* g_Allocator = NULL;
|
||||
@@ -329,7 +331,7 @@ static void glfw_error_callback(int error, const char* description)
|
||||
fprintf(stderr, "Glfw Error %d: %s\n", error, description);
|
||||
}
|
||||
|
||||
int startImgui(void* customState, void (*const initFunc)(void), void (*const drawFunc)(DrawData&, void*))
|
||||
int startImgui(void* customState, void (*const initFunc)(DrawData&, void*), void (*const drawFunc)(DrawData&, void*), const char* title, int windowWidth, int windowHeight)
|
||||
{
|
||||
// Setup GLFW window
|
||||
glfwSetErrorCallback(glfw_error_callback);
|
||||
@@ -337,7 +339,7 @@ int startImgui(void* customState, void (*const initFunc)(void), void (*const dra
|
||||
return 1;
|
||||
|
||||
glfwWindowHint(GLFW_CLIENT_API, GLFW_NO_API);
|
||||
GLFWwindow* window = glfwCreateWindow(1280, 720, "Dear ImGui GLFW+Vulkan example", NULL, NULL);
|
||||
GLFWwindow* window = glfwCreateWindow(windowWidth, windowHeight, title, NULL, NULL);
|
||||
|
||||
// Setup Vulkan
|
||||
if (!glfwVulkanSupported())
|
||||
@@ -404,7 +406,12 @@ int startImgui(void* customState, void (*const initFunc)(void), void (*const dra
|
||||
//ImFont* font = io.Fonts->AddFontFromFileTTF("c:\\Windows\\Fonts\\ArialUni.ttf", 18.0f, NULL, io.Fonts->GetGlyphRangesJapanese());
|
||||
//IM_ASSERT(font != NULL);
|
||||
|
||||
initFunc();
|
||||
// Our state
|
||||
DrawData drawData{};
|
||||
drawData.window_handle = glfwGetWin32Window(window);
|
||||
drawData.window_size = getWindowSize(window);
|
||||
|
||||
initFunc(drawData, customState);
|
||||
|
||||
// Upload Fonts
|
||||
{
|
||||
@@ -436,9 +443,6 @@ int startImgui(void* customState, void (*const initFunc)(void), void (*const dra
|
||||
ImGui_ImplVulkan_DestroyFontUploadObjects();
|
||||
}
|
||||
|
||||
// Our state
|
||||
DrawData drawData{};
|
||||
|
||||
// Main loop
|
||||
while (!glfwWindowShouldClose(window))
|
||||
{
|
||||
@@ -468,8 +472,16 @@ int startImgui(void* customState, void (*const initFunc)(void), void (*const dra
|
||||
ImGui_ImplGlfw_NewFrame();
|
||||
ImGui::NewFrame();
|
||||
|
||||
ImVec2 prevWindowSize = getWindowSize(window);
|
||||
drawData.window_size = prevWindowSize;
|
||||
|
||||
drawFunc(drawData, customState);
|
||||
|
||||
if (drawData.window_size.x != prevWindowSize.x || drawData.window_size.y != prevWindowSize.y)
|
||||
{
|
||||
glfwSetWindowSize(window, drawData.window_size.x, drawData.window_size.y);
|
||||
}
|
||||
|
||||
// Rendering
|
||||
ImGui::Render();
|
||||
ImDrawData* draw_data = ImGui::GetDrawData();
|
||||
@@ -500,3 +512,11 @@ int startImgui(void* customState, void (*const initFunc)(void), void (*const dra
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
ImVec2 getWindowSize(GLFWwindow* window)
|
||||
{
|
||||
int window_width;
|
||||
int window_height;
|
||||
glfwGetWindowSize(window, &window_width, &window_height);
|
||||
return ImVec2(window_width, window_height);
|
||||
}
|
||||
@@ -1,10 +1,16 @@
|
||||
#pragma once
|
||||
|
||||
#include <Windows.h>
|
||||
#include "imgui_impl_glfw.h"
|
||||
#include "imgui/headers/imgui.h"
|
||||
|
||||
class DrawData {
|
||||
public:
|
||||
ImVec4 clear_color;
|
||||
HWND window_handle = nullptr;
|
||||
ImVec4 clear_color = {};
|
||||
ImVec2 window_size = {};
|
||||
};
|
||||
|
||||
int startImgui(void* customState, void (*const initFunc)(void), void (* const drawFunc)(DrawData&, void*));
|
||||
int startImgui(void* customState, void (*const initFunc)(DrawData&, void*), void (* const drawFunc)(DrawData&, void*), const char* title, int windowWidth, int windowHeight);
|
||||
|
||||
ImVec2 getWindowSize(GLFWwindow* window);
|
||||
|
||||
@@ -10,15 +10,15 @@
|
||||
|
||||
int main()
|
||||
{
|
||||
CustomDrawData customDrawData{};
|
||||
ApplicationData applicationData{};
|
||||
|
||||
startImgui(&customDrawData, init, draw);
|
||||
startImgui(&applicationData, init, draw, "Node Test", 1280, 720);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Setup before first draw.
|
||||
/// </summary>
|
||||
void init()
|
||||
void init(DrawData& drawData, void* customData)
|
||||
{
|
||||
ImGuiIO& io = ImGui::GetIO();
|
||||
io.Fonts->AddFontFromFileTTF("Montserrat-Regular.ttf", 16.0f);
|
||||
@@ -27,118 +27,120 @@ void init()
|
||||
/// <summary>
|
||||
/// Draw main application content.
|
||||
/// </summary>
|
||||
void draw(DrawData& drawData, void* customDataVoid)
|
||||
void draw(DrawData& drawData, void* customData)
|
||||
{
|
||||
CustomDrawData* customData = static_cast<CustomDrawData*>(customDataVoid);
|
||||
|
||||
bool isDraggingLine = false;
|
||||
ImVec2 lineStartPos = ImVec2{};
|
||||
ApplicationData* applicationData = static_cast<ApplicationData*>(customData);
|
||||
|
||||
// Top menu bar
|
||||
ImGui::BeginMainMenuBar();
|
||||
if (ImGui::Button("Add Node"))
|
||||
{
|
||||
std::string name{ "Node " };
|
||||
name.append(std::to_string(customData->nodes.size() + 1));
|
||||
customData->nodes.push_back(NodeWindow(name));
|
||||
name.append(std::to_string(applicationData->nodes.size() + 1));
|
||||
applicationData->nodes.push_back(NodeWindow(name));
|
||||
}
|
||||
ImGui::EndMainMenuBar();
|
||||
|
||||
// Draw all node windows
|
||||
auto nodeIterator = customData->nodes.begin();
|
||||
while (nodeIterator != customData->nodes.end())
|
||||
bool isDraggingLine = false;
|
||||
ImVec2 lineStartPos = ImVec2{};
|
||||
|
||||
auto nodeIterator = applicationData->nodes.begin();
|
||||
while (nodeIterator != applicationData->nodes.end())
|
||||
{
|
||||
NodeWindow& node = *nodeIterator;
|
||||
|
||||
bool nodeOpen;
|
||||
ImGui::Begin(node.title.c_str(), &nodeOpen, ImGuiWindowFlags_NoResize | ImGuiWindowFlags_AlwaysAutoResize);
|
||||
if (!nodeOpen)
|
||||
{
|
||||
auto triggerIterator = node.triggers.begin();
|
||||
while (triggerIterator != node.triggers.end())
|
||||
if (!nodeOpen)
|
||||
{
|
||||
triggerIterator = cleanEraseElement(node.triggers, triggerIterator, customData);
|
||||
cleanEreaseNodeElements(*nodeIterator, applicationData);
|
||||
nodeIterator = applicationData->nodes.erase(nodeIterator);
|
||||
ImGui::End();
|
||||
break; // TODO: contine creates bug with closing too many windows???
|
||||
}
|
||||
|
||||
auto alertIterator = node.alerts.begin();
|
||||
while (alertIterator != node.alerts.end())
|
||||
{
|
||||
alertIterator = cleanEraseElement(node.alerts, alertIterator, customData);
|
||||
}
|
||||
|
||||
nodeIterator = customData->nodes.erase(nodeIterator);
|
||||
ImGui::End();
|
||||
break; // TODO: contine will create problems with closing too many windows?
|
||||
}
|
||||
|
||||
// Expand clip rect to allow circles on edges
|
||||
ImVec2 contentMin = ImGui::GetWindowPos();
|
||||
ImVec2 contentMax = ImVec2{ contentMin.x + ImGui::GetWindowWidth(), contentMin.y + ImGui::GetWindowHeight() };
|
||||
ImGui::PushClipRect(ImVec2{ contentMin.x - 15, contentMin.y }, ImVec2{ contentMax.x + 15, contentMax.y }, false);
|
||||
|
||||
auto alertIterator = node.alerts.begin();
|
||||
while (alertIterator != node.alerts.end())
|
||||
{
|
||||
if (drawCircle(0, CircleDragType::Source, alertIterator._Ptr, &alertIterator->position))
|
||||
{
|
||||
isDraggingLine = true;
|
||||
lineStartPos = alertIterator->position;
|
||||
ImGui::Text(alertIterator->name.c_str());
|
||||
|
||||
ConnectionPayload payload{ alertIterator->id };
|
||||
|
||||
ImGui::SetDragDropPayload("NODE_CONNECTION", (void*)&payload, sizeof(ConnectionPayload));
|
||||
ImGui::EndDragDropSource();
|
||||
}
|
||||
|
||||
ImGui::Text(alertIterator->name.c_str());
|
||||
if (ImGui::IsWindowHovered() || ImGui::IsWindowFocused())
|
||||
{
|
||||
if (inlineButton("x", alertIterator._Ptr))
|
||||
if (ImGui::IsWindowHovered() || ImGui::IsWindowFocused())
|
||||
{
|
||||
alertIterator = cleanEraseElement(node.alerts, alertIterator, customData);
|
||||
continue;
|
||||
if (inlineButton("x", alertIterator._Ptr))
|
||||
{
|
||||
alertIterator = cleanEraseElement(node.alerts, alertIterator, applicationData);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
}
|
||||
alertIterator++;
|
||||
}
|
||||
|
||||
auto triggerIterator = node.triggers.begin();
|
||||
while (triggerIterator != node.triggers.end())
|
||||
{
|
||||
if (drawCircle(-ImGui::GetStyle().WindowPadding.x, CircleDragType::Target, triggerIterator._Ptr, &triggerIterator->position))
|
||||
{
|
||||
if (const ImGuiPayload* payload = ImGui::AcceptDragDropPayload("NODE_CONNECTION"))
|
||||
else
|
||||
{
|
||||
ConnectionPayload* payloadData = static_cast<ConnectionPayload*>(payload->Data);
|
||||
|
||||
customData->connections.push_back(NodeConnection { payloadData->sourceID, triggerIterator->id });
|
||||
invisibleInlineButton("x", "x");
|
||||
}
|
||||
ImGui::EndDragDropTarget();
|
||||
}
|
||||
|
||||
ImGui::Text(triggerIterator->name.c_str());
|
||||
if (ImGui::IsWindowHovered() || ImGui::IsWindowFocused())
|
||||
{
|
||||
if (inlineButton("x", triggerIterator._Ptr))
|
||||
ImGui::SameLine();
|
||||
drawCircle(&alertIterator->position);
|
||||
|
||||
float lineHeight = ImGui::GetTextLineHeight();
|
||||
ImVec2 dragAreaSize = ImVec2{ lineHeight, lineHeight };
|
||||
invisibleDragArea(alertIterator._Ptr, dragAreaSize);
|
||||
if (ImGui::BeginDragDropSource())
|
||||
{
|
||||
triggerIterator = cleanEraseElement(node.triggers, triggerIterator, customData);
|
||||
continue;
|
||||
isDraggingLine = true;
|
||||
lineStartPos = alertIterator->position;
|
||||
ImGui::Text(alertIterator->name.c_str());
|
||||
|
||||
ConnectionPayload payload{ alertIterator->id };
|
||||
|
||||
ImGui::SetDragDropPayload("NODE_CONNECTION", (void*)&payload, sizeof(ConnectionPayload));
|
||||
ImGui::EndDragDropSource();
|
||||
}
|
||||
|
||||
alertIterator++;
|
||||
}
|
||||
triggerIterator++;
|
||||
}
|
||||
|
||||
if (ImGui::Button("New Alert"))
|
||||
{
|
||||
node.alerts.push_back(NodeElement("Today, 18:00"));
|
||||
}
|
||||
if (ImGui::Button("New Trigger"))
|
||||
{
|
||||
node.triggers.push_back(NodeElement("Doot"));
|
||||
}
|
||||
auto triggerIterator = node.triggers.begin();
|
||||
while (triggerIterator != node.triggers.end())
|
||||
{
|
||||
drawCircle(&triggerIterator->position);
|
||||
|
||||
ImGui::PopClipRect();
|
||||
float lineHeight = ImGui::GetTextLineHeight();
|
||||
ImVec2 dragAreaSize = ImVec2{ lineHeight, lineHeight };
|
||||
invisibleDragArea(triggerIterator._Ptr, dragAreaSize);
|
||||
if (ImGui::BeginDragDropTarget())
|
||||
{
|
||||
if (const ImGuiPayload* payload = ImGui::AcceptDragDropPayload("NODE_CONNECTION"))
|
||||
{
|
||||
ConnectionPayload* payloadData = static_cast<ConnectionPayload*>(payload->Data);
|
||||
applicationData->addConnection(payloadData->sourceID, triggerIterator->id);
|
||||
}
|
||||
ImGui::EndDragDropTarget();
|
||||
}
|
||||
|
||||
ImGui::SameLine();
|
||||
ImGui::Text(triggerIterator->name.c_str());
|
||||
if (ImGui::IsWindowHovered() || ImGui::IsWindowFocused())
|
||||
{
|
||||
if (inlineButton("x", triggerIterator._Ptr))
|
||||
{
|
||||
triggerIterator = cleanEraseElement(node.triggers, triggerIterator, applicationData);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
triggerIterator++;
|
||||
}
|
||||
|
||||
if (ImGui::Button("New Alert"))
|
||||
{
|
||||
node.alerts.push_back(NodeElement("Today, 18:00"));
|
||||
}
|
||||
if (ImGui::Button("New Trigger"))
|
||||
{
|
||||
node.triggers.push_back(NodeElement("Doot"));
|
||||
}
|
||||
}
|
||||
ImGui::End();
|
||||
|
||||
nodeIterator++;
|
||||
}
|
||||
|
||||
@@ -151,11 +153,11 @@ void draw(DrawData& drawData, void* customDataVoid)
|
||||
|
||||
// Draw connected lines in background
|
||||
ImDrawList* bgDrawList = ImGui::GetBackgroundDrawList();
|
||||
for (NodeConnection& nodeConnection : customData->connections)
|
||||
for (NodeConnection& nodeConnection : applicationData->connections)
|
||||
{
|
||||
ImVec2 sourcePos = ImVec2{ 0, 0 };
|
||||
ImVec2 targetPos = ImVec2{ 0, 0 };
|
||||
for (auto node : customData->nodes)
|
||||
for (auto node : applicationData->nodes)
|
||||
{
|
||||
for (auto alert : node.alerts)
|
||||
{
|
||||
@@ -177,42 +179,35 @@ void draw(DrawData& drawData, void* customDataVoid)
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Draws a small circle in the same row.
|
||||
/// Creates an invisible button that does nothing, but can be used for drag/drop operations.
|
||||
/// </summary>
|
||||
/// <param name="outCirclePos">Returns the position of the circle.</param>
|
||||
/// <returns>True if an event matching the dragType has occurred.</returns>
|
||||
bool drawCircle(float xOffset, CircleDragType dragType, const void* id, ImVec2* outCirclePos)
|
||||
void invisibleDragArea(const void* id, ImVec2& size)
|
||||
{
|
||||
auto cursor = ImGui::GetCursorScreenPos();
|
||||
ImDrawList* drawList = ImGui::GetWindowDrawList();
|
||||
|
||||
float circleRadius = 5;
|
||||
float yCircleOffset = ImGui::GetTextLineHeight() / 2.;
|
||||
ImVec2 circlePos = ImVec2{ cursor.x + xOffset, cursor.y + yCircleOffset };
|
||||
|
||||
drawList->AddCircleFilled(circlePos, 5, IM_COL32_WHITE);
|
||||
|
||||
ImVec2 originalPos = ImGui::GetCursorPos();
|
||||
ImGui::SetCursorPosX(xOffset);
|
||||
ImGui::PushID(id);
|
||||
ImGui::InvisibleButton("", ImVec2{ 15, 15 });
|
||||
ImGui::InvisibleButton("", size);
|
||||
ImGui::PopID();
|
||||
ImGui::SetCursorPos(originalPos);
|
||||
}
|
||||
|
||||
if (outCirclePos != nullptr)
|
||||
{
|
||||
*outCirclePos = circlePos;
|
||||
}
|
||||
/// <summary>
|
||||
/// Draws a small circle at the current cursor position.
|
||||
/// </summary>
|
||||
/// <param name="outCircleCenter">Returns the center position of the circle.</param>
|
||||
void drawCircle(ImVec2* outCircleCenter = nullptr)
|
||||
{
|
||||
float lineHeight = ImGui::GetTextLineHeight();
|
||||
float circleRadius = (lineHeight / 2.) * 0.75;
|
||||
float circleOffset = lineHeight / 2.;
|
||||
|
||||
if (dragType == CircleDragType::Source && ImGui::BeginDragDropSource())
|
||||
ImVec2 cursor = ImGui::GetCursorScreenPos();
|
||||
ImVec2 circlePos = ImVec2{ cursor.x + circleOffset, cursor.y + circleOffset };
|
||||
|
||||
ImDrawList* drawList = ImGui::GetWindowDrawList();
|
||||
drawList->AddCircleFilled(circlePos, circleRadius, IM_COL32_WHITE);
|
||||
|
||||
if (outCircleCenter != nullptr)
|
||||
{
|
||||
return true;
|
||||
*outCircleCenter = circlePos;
|
||||
}
|
||||
if (dragType == CircleDragType::Target && ImGui::BeginDragDropTarget())
|
||||
{
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -222,23 +217,27 @@ bool inlineButton(const char* title, const void* id)
|
||||
{
|
||||
ImGui::SameLine();
|
||||
ImGui::PushID(id);
|
||||
if (ImGui::SmallButton(title))
|
||||
{
|
||||
ImGui::PopID();
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
ImGui::PopID();
|
||||
return false;
|
||||
}
|
||||
|
||||
bool result = ImGui::SmallButton(title);
|
||||
|
||||
ImGui::PopID();
|
||||
return result;
|
||||
}
|
||||
|
||||
bool invisibleInlineButton(const char* title, const char* id)
|
||||
{
|
||||
ImGui::SameLine();
|
||||
ImVec2 padding = ImGui::GetStyle().FramePadding;
|
||||
ImVec2 size = ImGui::CalcTextSize(title);
|
||||
size.x += padding.x * 2.;
|
||||
return ImGui::InvisibleButton(id, size);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Removes any attached connections before erasing this NodeElement from a vector.
|
||||
/// </summary>
|
||||
/// <returns>Continued iterator</returns>
|
||||
std::vector<NodeElement>::iterator cleanEraseElement(std::vector<NodeElement>& elements, std::vector<NodeElement>::iterator toErase, CustomDrawData* data)
|
||||
std::vector<NodeElement>::iterator cleanEraseElement(std::vector<NodeElement>& elements, std::vector<NodeElement>::iterator toErase, ApplicationData* data)
|
||||
{
|
||||
auto connectionIterator = data->connections.begin();
|
||||
while (connectionIterator != data->connections.end())
|
||||
@@ -253,17 +252,46 @@ std::vector<NodeElement>::iterator cleanEraseElement(std::vector<NodeElement>& e
|
||||
return elements.erase(toErase);
|
||||
}
|
||||
|
||||
NodeElement::NodeElement(std::string name)
|
||||
void cleanEreaseNodeElements(NodeWindow& node, ApplicationData* data)
|
||||
{
|
||||
this->id = nodeIdCounter;
|
||||
nodeIdCounter++;
|
||||
this->name = name;
|
||||
this->position = ImVec2{ 0, 0 };
|
||||
auto triggerIterator = node.triggers.begin();
|
||||
while (triggerIterator != node.triggers.end())
|
||||
{
|
||||
triggerIterator = cleanEraseElement(node.triggers, triggerIterator, data);
|
||||
}
|
||||
auto alertIterator = node.alerts.begin();
|
||||
while (alertIterator != node.alerts.end())
|
||||
{
|
||||
alertIterator = cleanEraseElement(node.alerts, alertIterator, data);
|
||||
}
|
||||
}
|
||||
|
||||
NodeWindow::NodeWindow(std::string title)
|
||||
NodeElement::NodeElement(std::string name) : name(name)
|
||||
{
|
||||
this->title = title;
|
||||
this->alerts = std::vector<NodeElement>();
|
||||
this->triggers = std::vector<NodeElement>();
|
||||
this->id = globalNodeIdCounter;
|
||||
globalNodeIdCounter++;
|
||||
}
|
||||
|
||||
NodeWindow::NodeWindow(std::string title) : title(title)
|
||||
{
|
||||
}
|
||||
|
||||
void ApplicationData::addConnection(int sourceID, int targetID)
|
||||
{
|
||||
// Remove duplicate connections
|
||||
auto connectionIterator = connections.begin();
|
||||
while (connectionIterator != connections.end())
|
||||
{
|
||||
// Currently only remove on exact match, maybe add some other constraints later
|
||||
if (connectionIterator->sourceID == sourceID && connectionIterator->targetID == targetID)
|
||||
{
|
||||
connectionIterator = connections.erase(connectionIterator);
|
||||
continue;
|
||||
}
|
||||
|
||||
connectionIterator++;
|
||||
}
|
||||
|
||||
// Add new connection
|
||||
connections.push_back(NodeConnection{ sourceID, targetID });
|
||||
}
|
||||
|
||||
@@ -2,39 +2,41 @@
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
int nodeIdCounter = 0;
|
||||
int globalNodeIdCounter = 0;
|
||||
|
||||
class NodeElement {
|
||||
public:
|
||||
int id;
|
||||
std::string name;
|
||||
ImVec2 position;
|
||||
int id = -1;
|
||||
std::string name = {};
|
||||
ImVec2 position = {};
|
||||
|
||||
NodeElement(std::string name);
|
||||
};
|
||||
|
||||
class NodeWindow {
|
||||
public:
|
||||
std::string title;
|
||||
std::vector<NodeElement> alerts;
|
||||
std::vector<NodeElement> triggers;
|
||||
std::string title = {};
|
||||
std::vector<NodeElement> alerts = {};
|
||||
std::vector<NodeElement> triggers = {};
|
||||
|
||||
NodeWindow(std::string title);
|
||||
};
|
||||
|
||||
typedef struct NodeConnection {
|
||||
int sourceID;
|
||||
int targetID;
|
||||
struct NodeConnection {
|
||||
int sourceID = -1;
|
||||
int targetID = -1;
|
||||
};
|
||||
|
||||
typedef struct ConnectionPayload {
|
||||
int sourceID;
|
||||
struct ConnectionPayload {
|
||||
int sourceID = -1;
|
||||
};
|
||||
|
||||
class CustomDrawData {
|
||||
class ApplicationData {
|
||||
public:
|
||||
std::vector<NodeWindow> nodes;
|
||||
std::vector<NodeConnection> connections;
|
||||
std::vector<NodeWindow> nodes = {};
|
||||
std::vector<NodeConnection> connections = {};
|
||||
|
||||
void addConnection(int sourceID, int targetID);
|
||||
};
|
||||
|
||||
enum class CircleDragType
|
||||
@@ -44,8 +46,12 @@ enum class CircleDragType
|
||||
Target
|
||||
};
|
||||
|
||||
void init();
|
||||
void init(DrawData& drawData, void* customData);
|
||||
void draw(DrawData& drawData, void* customDataVoid);
|
||||
bool drawCircle(float xOffset, CircleDragType dragType, const void* id, ImVec2* outCirclePos = nullptr);
|
||||
|
||||
void invisibleDragArea(const void* id, ImVec2& size);
|
||||
void drawCircle(ImVec2* outCircleCenter);
|
||||
bool inlineButton(const char* title, const void* id);
|
||||
std::vector<NodeElement>::iterator cleanEraseElement(std::vector<NodeElement>& vector, std::vector<NodeElement>::iterator toErase, CustomDrawData* data);
|
||||
bool invisibleInlineButton(const char* title, const char* id);
|
||||
std::vector<NodeElement>::iterator cleanEraseElement(std::vector<NodeElement>& vector, std::vector<NodeElement>::iterator toErase, ApplicationData* data);
|
||||
void cleanEreaseNodeElements(NodeWindow& node, ApplicationData* data);
|
||||
|
||||
Reference in New Issue
Block a user