Compare commits
138 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
81f0a91569 | ||
|
|
25aacc9511 | ||
|
|
8fee7a282b | ||
|
|
1312a5fa86 | ||
|
|
6a7f32a29d | ||
| a16fcf3342 | |||
| d9018e2d2e | |||
|
|
9cc4bdefd0 | ||
|
|
2d4fd3493e | ||
|
|
59f99d0b99 | ||
|
|
3d29005567 | ||
|
|
68f0f2e769 | ||
|
|
1884e0ca7a | ||
|
|
4fc5dfdc76 | ||
|
|
33d2cc9ef1 | ||
|
|
19c5443e9e | ||
|
|
27cdee0c14 | ||
|
|
cefa0ac18c | ||
|
|
303877655f | ||
|
|
08988fe3ec | ||
|
|
fec074ad30 | ||
|
|
5e89954094 | ||
|
|
277e78c14b | ||
|
|
45cb6be3c5 | ||
|
|
d24e06f101 | ||
|
|
eff832bb8c | ||
|
|
32deea8341 | ||
|
|
2b45f69ff4 | ||
|
|
409d52c120 | ||
|
|
2abed18784 | ||
|
|
c2a242022a | ||
|
|
57cbbf24b1 | ||
|
|
721dd361fa | ||
|
|
d062a087c5 | ||
|
|
6f0a26a86c | ||
|
|
f00904dd76 | ||
|
|
708ed599ae | ||
|
|
8d24e19989 | ||
| e0f4fdd959 | |||
|
|
16745c9bf8 | ||
|
|
f5984141fd | ||
|
|
cb24322fc1 | ||
|
|
ca81c07600 | ||
|
|
b3958e9d52 | ||
|
|
441a3dbfd9 | ||
| 095e73a2b4 | |||
|
|
321c2d9a3c | ||
|
|
f50ee6e8f1 | ||
|
|
3f265cdb46 | ||
|
|
7a38fd0676 | ||
|
|
26cfa07f77 | ||
|
|
4c884d019d | ||
|
|
1e8b6e599c | ||
|
|
cdc720b8a7 | ||
|
|
1e8ce19b16 | ||
|
|
d7011f0e77 | ||
|
|
77c7daa67c | ||
| e3c936648b | |||
|
|
1fefba66e7 | ||
|
|
594fb346e1 | ||
|
|
3833c137f6 | ||
|
|
912eb7950c | ||
| 4146cdd049 | |||
|
|
f5a0a46453 | ||
|
|
8f94bdd488 | ||
|
|
f37296d560 | ||
| fd292491c7 | |||
|
|
380381c7d1 | ||
|
|
3f9a91b0ab | ||
|
|
985994a291 | ||
|
|
e37128d657 | ||
|
|
4c2a262478 | ||
|
|
3eba4cc1ac | ||
|
|
91b88c0568 | ||
|
|
6f7d09ce45 | ||
|
|
5caf6bf017 | ||
|
|
d399f1d302 | ||
|
|
77215fc996 | ||
|
|
2f4d0e7541 | ||
|
|
89233e98b5 | ||
|
|
b890a76e20 | ||
|
|
3c7cf5515f | ||
|
|
ebe6f18898 | ||
|
|
cab7402104 | ||
|
|
862c618b7e | ||
|
|
448b212ad9 | ||
|
|
03d597b0ac | ||
|
|
75830dc6dd | ||
|
|
e18c0a62de | ||
|
|
047a91452e | ||
|
|
fdf07d6c33 | ||
|
|
4b2b86f420 | ||
|
|
c6781df90a | ||
|
|
aef2b2a707 | ||
| 0bace131e8 | |||
|
|
4e7c31849d | ||
|
|
3d56d5f0cc | ||
| 54bbc7399a | |||
|
|
a23af16349 | ||
|
|
5c8fa2e8ab | ||
|
|
aff8880595 | ||
|
|
2e7345f11d | ||
|
|
ecd990e94e | ||
|
|
2836e73812 | ||
|
|
df167556fb | ||
|
|
72d0df7d46 | ||
|
|
1dfdf4c392 | ||
|
|
9cf96ad6f9 | ||
|
|
eb948dfd63 | ||
| c886bfd7d2 | |||
|
|
3fd3f3edc5 | ||
|
|
7cb7ed73ea | ||
|
|
2521f37408 | ||
|
|
bfe6668d0c | ||
|
|
38f24ce3e4 | ||
|
|
218fad7541 | ||
| af68ee61e1 | |||
| b40b2c031a | |||
| aa32ff7e84 | |||
|
|
28cac7ff83 | ||
|
|
055e73183a | ||
|
|
a048605011 | ||
|
|
260ec5bb93 | ||
|
|
2a2a16fd17 | ||
|
|
b421412cac | ||
|
|
5bae40d3c3 | ||
|
|
d06a5ebcfa | ||
|
|
e2581cea8b | ||
|
|
d602fbacd3 | ||
|
|
2dcb9dd1c7 | ||
|
|
d3d5595422 | ||
|
|
596bc66ce6 | ||
|
|
3a7b43a63a | ||
|
|
83a2bf0b4e | ||
|
|
695fc10b8f | ||
| feea7c2ecc | |||
|
|
1be5d6e821 | ||
|
|
2d31313594 |
30
.clang-format
Normal file
@@ -0,0 +1,30 @@
|
|||||||
|
---
|
||||||
|
IndentWidth: 4
|
||||||
|
ColumnLimit: 120
|
||||||
|
UseTab: Never
|
||||||
|
---
|
||||||
|
Language: Cpp
|
||||||
|
DerivePointerAlignment: false
|
||||||
|
PointerAlignment: Left
|
||||||
|
AlignAfterOpenBracket: Align
|
||||||
|
AlignConsecutiveAssignments: false
|
||||||
|
BreakBeforeBraces: Allman
|
||||||
|
IndentCaseLabels: false
|
||||||
|
AllowShortBlocksOnASingleLine: true
|
||||||
|
AlignOperands: true
|
||||||
|
AlignTrailingComments: true
|
||||||
|
AlwaysBreakBeforeMultilineStrings: true
|
||||||
|
AlwaysBreakTemplateDeclarations: true
|
||||||
|
BreakConstructorInitializersBeforeComma: true
|
||||||
|
BreakStringLiterals: true
|
||||||
|
AlwaysBreakAfterReturnType: None
|
||||||
|
AlwaysBreakAfterDefinitionReturnType: None
|
||||||
|
AllowShortFunctionsOnASingleLine: All
|
||||||
|
Cpp11BracedListStyle: true
|
||||||
|
NamespaceIndentation: None
|
||||||
|
BinPackArguments: true
|
||||||
|
BinPackParameters: true
|
||||||
|
SortIncludes: false
|
||||||
|
AccessModifierOffset: -4
|
||||||
|
ConstructorInitializerIndentWidth: 0
|
||||||
|
ConstructorInitializerAllOnOneLineOrOnePerLine: true
|
||||||
@@ -12,7 +12,7 @@
|
|||||||
<true/>
|
<true/>
|
||||||
<key>com.apple.security.application-groups</key>
|
<key>com.apple.security.application-groups</key>
|
||||||
<array>
|
<array>
|
||||||
<string>group.io.github.axiodl.Amuse.AudioGroups</string>
|
<string>group.com.axiodl.Amuse.AudioGroups</string>
|
||||||
</array>
|
</array>
|
||||||
</dict>
|
</dict>
|
||||||
</plist>
|
</plist>
|
||||||
|
|||||||
@@ -218,7 +218,7 @@
|
|||||||
|
|
||||||
- (void)pumpTimer:(NSTimer*)timer
|
- (void)pumpTimer:(NSTimer*)timer
|
||||||
{
|
{
|
||||||
amuseEngine->pumpEngine();
|
booEngine->pumpAndMixVoices();
|
||||||
}
|
}
|
||||||
|
|
||||||
- (BOOL)applicationShouldTerminateAfterLastWindowClosed:(NSApplication *)sender
|
- (BOOL)applicationShouldTerminateAfterLastWindowClosed:(NSApplication *)sender
|
||||||
@@ -251,7 +251,7 @@
|
|||||||
{
|
{
|
||||||
__block NSOpenPanel* panel = [NSOpenPanel openPanel];
|
__block NSOpenPanel* panel = [NSOpenPanel openPanel];
|
||||||
[panel beginSheetModalForWindow:mainWindow completionHandler:^(NSInteger result) {
|
[panel beginSheetModalForWindow:mainWindow completionHandler:^(NSInteger result) {
|
||||||
if (result == NSFileHandlingPanelOKButton)
|
if (result == NSModalResponseOK)
|
||||||
{
|
{
|
||||||
[self importURL:panel.URL];
|
[self importURL:panel.URL];
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -10,7 +10,7 @@
|
|||||||
<true/>
|
<true/>
|
||||||
<key>com.apple.security.application-groups</key>
|
<key>com.apple.security.application-groups</key>
|
||||||
<array>
|
<array>
|
||||||
<string>group.io.github.axiodl.Amuse.AudioGroups</string>
|
<string>group.com.axiodl.Amuse.AudioGroups</string>
|
||||||
</array>
|
</array>
|
||||||
</dict>
|
</dict>
|
||||||
</plist>
|
</plist>
|
||||||
|
|||||||
@@ -42,9 +42,13 @@ struct AudioGroupDataCollection
|
|||||||
uint32_t absOffs;
|
uint32_t absOffs;
|
||||||
uint32_t active;
|
uint32_t active;
|
||||||
MetaData(amuse::DataFormat fmtIn, uint32_t absOffsIn, uint32_t activeIn)
|
MetaData(amuse::DataFormat fmtIn, uint32_t absOffsIn, uint32_t activeIn)
|
||||||
: fmt(fmtIn), absOffs(absOffsIn), active(activeIn) {}
|
: fmt(fmtIn), absOffs(absOffsIn), active(activeIn)
|
||||||
|
{
|
||||||
|
}
|
||||||
MetaData(athena::io::FileReader& r)
|
MetaData(athena::io::FileReader& r)
|
||||||
: fmt(amuse::DataFormat(r.readUint32Little())), absOffs(r.readUint32Little()), active(r.readUint32Little()) {}
|
: fmt(amuse::DataFormat(r.readUint32Little())), absOffs(r.readUint32Little()), active(r.readUint32Little())
|
||||||
|
{
|
||||||
|
}
|
||||||
};
|
};
|
||||||
std::experimental::optional<MetaData> m_metaData;
|
std::experimental::optional<MetaData> m_metaData;
|
||||||
|
|
||||||
@@ -60,8 +64,11 @@ struct AudioGroupDataCollection
|
|||||||
bool loadSamp(AudioGroupFilePresenter* presenter);
|
bool loadSamp(AudioGroupFilePresenter* presenter);
|
||||||
bool loadMeta(AudioGroupFilePresenter* presenter);
|
bool loadMeta(AudioGroupFilePresenter* presenter);
|
||||||
|
|
||||||
AudioGroupDataCollection(const std::string& name, NSURL* proj, NSURL* pool, NSURL* sdir, NSURL* samp, NSURL* meta);
|
AudioGroupDataCollection(std::string_view name, NSURL* proj, NSURL* pool, NSURL* sdir, NSURL* samp, NSURL* meta);
|
||||||
bool isDataComplete() const {return m_projData.size() && m_poolData.size() && m_sdirData.size() && m_sampData.size() && m_metaData;}
|
bool isDataComplete() const
|
||||||
|
{
|
||||||
|
return m_projData.size() && m_poolData.size() && m_sdirData.size() && m_sampData.size() && m_metaData;
|
||||||
|
}
|
||||||
bool _attemptLoad(AudioGroupFilePresenter* presenter);
|
bool _attemptLoad(AudioGroupFilePresenter* presenter);
|
||||||
bool _indexData(AudioGroupFilePresenter* presenter);
|
bool _indexData(AudioGroupFilePresenter* presenter);
|
||||||
|
|
||||||
@@ -81,7 +88,7 @@ struct AudioGroupCollection
|
|||||||
void addCollection(AudioGroupFilePresenter* presenter,
|
void addCollection(AudioGroupFilePresenter* presenter,
|
||||||
std::vector<std::pair<std::string, amuse::IntrusiveAudioGroupData>>&& collection);
|
std::vector<std::pair<std::string, amuse::IntrusiveAudioGroupData>>&& collection);
|
||||||
void update(AudioGroupFilePresenter* presenter);
|
void update(AudioGroupFilePresenter* presenter);
|
||||||
bool doSearch(const std::string& str);
|
bool doSearch(std::string_view str);
|
||||||
bool doActiveFilter();
|
bool doActiveFilter();
|
||||||
void addSFX(std::vector<AudioGroupSFXToken*>& vecOut);
|
void addSFX(std::vector<AudioGroupSFXToken*>& vecOut);
|
||||||
void addSamples(std::vector<AudioGroupSampleToken*>& vecOut);
|
void addSamples(std::vector<AudioGroupSampleToken*>& vecOut);
|
||||||
@@ -119,8 +126,10 @@ struct AudioGroupCollection
|
|||||||
NSAttributedString* m_name;
|
NSAttributedString* m_name;
|
||||||
const std::pair<amuse::AudioGroupSampleDirectory::Entry, amuse::AudioGroupSampleDirectory::ADPCMParms>* m_sample;
|
const std::pair<amuse::AudioGroupSampleDirectory::Entry, amuse::AudioGroupSampleDirectory::ADPCMParms>* m_sample;
|
||||||
}
|
}
|
||||||
- (id)initWithName:(NSAttributedString*)name samp:(const std::pair<amuse::AudioGroupSampleDirectory::Entry,
|
- (id)
|
||||||
amuse::AudioGroupSampleDirectory::ADPCMParms>*)sample;
|
initWithName:(NSAttributedString*)name
|
||||||
|
samp:(const std::pair<amuse::AudioGroupSampleDirectory::Entry, amuse::AudioGroupSampleDirectory::ADPCMParms>*)
|
||||||
|
sample;
|
||||||
@end
|
@end
|
||||||
|
|
||||||
@interface AudioGroupToken : NSObject
|
@interface AudioGroupToken : NSObject
|
||||||
@@ -149,7 +158,8 @@ struct AudioGroupCollection
|
|||||||
std::vector<AudioGroupSampleToken*> m_sampleTableData;
|
std::vector<AudioGroupSampleToken*> m_sampleTableData;
|
||||||
}
|
}
|
||||||
- (id)initWithAudioGroupClient:(id<AudioGroupClient>)client;
|
- (id)initWithAudioGroupClient:(id<AudioGroupClient>)client;
|
||||||
- (BOOL)addCollectionName:(std::string&&)name items:(std::vector<std::pair<std::string, amuse::IntrusiveAudioGroupData>>&&)collection;
|
- (BOOL)addCollectionName:(std::string&&)name
|
||||||
|
items:(std::vector<std::pair<std::string, amuse::IntrusiveAudioGroupData>>&&)collection;
|
||||||
- (void)update;
|
- (void)update;
|
||||||
- (void)resetIterators;
|
- (void)resetIterators;
|
||||||
- (void)setSearchFilter:(NSString*)str;
|
- (void)setSearchFilter:(NSString*)str;
|
||||||
|
|||||||
@@ -161,13 +161,13 @@ void AudioGroupCollection::update(AudioGroupFilePresenter* presenter)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool AudioGroupCollection::doSearch(const std::string& str)
|
bool AudioGroupCollection::doSearch(std::string_view str)
|
||||||
{
|
{
|
||||||
bool ret = false;
|
bool ret = false;
|
||||||
m_filterGroups.clear();
|
m_filterGroups.clear();
|
||||||
m_filterGroups.reserve(m_groups.size());
|
m_filterGroups.reserve(m_groups.size());
|
||||||
for (auto it = m_groups.begin() ; it != m_groups.end() ; ++it)
|
for (auto it = m_groups.begin() ; it != m_groups.end() ; ++it)
|
||||||
if (str.empty() || StrToLower(it->first).find(str) != std::string::npos)
|
if (str.empty() || StrToLower(it->first).find(str.data()) != std::string::npos)
|
||||||
{
|
{
|
||||||
m_filterGroups.push_back(it);
|
m_filterGroups.push_back(it);
|
||||||
ret = true;
|
ret = true;
|
||||||
@@ -239,7 +239,7 @@ void AudioGroupCollection::addSamples(std::vector<AudioGroupSampleToken*>& vecOu
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
AudioGroupDataCollection::AudioGroupDataCollection(const std::string& name, NSURL* proj, NSURL* pool,
|
AudioGroupDataCollection::AudioGroupDataCollection(std::string_view name, NSURL* proj, NSURL* pool,
|
||||||
NSURL* sdir, NSURL* samp, NSURL* meta)
|
NSURL* sdir, NSURL* samp, NSURL* meta)
|
||||||
: m_name(name), m_proj(proj), m_pool(pool), m_sdir(sdir), m_samp(samp), m_meta(meta),
|
: m_name(name), m_proj(proj), m_pool(pool), m_sdir(sdir), m_samp(samp), m_meta(meta),
|
||||||
m_token([[AudioGroupDataToken alloc] initWithDataCollection:this]) {}
|
m_token([[AudioGroupDataToken alloc] initWithDataCollection:this]) {}
|
||||||
@@ -849,7 +849,7 @@ bool AudioGroupDataCollection::loadMeta(AudioGroupFilePresenter* presenter)
|
|||||||
- (id)initWithAudioGroupClient:(id<AudioGroupClient>)client
|
- (id)initWithAudioGroupClient:(id<AudioGroupClient>)client
|
||||||
{
|
{
|
||||||
m_audioGroupClient = client;
|
m_audioGroupClient = client;
|
||||||
m_groupURL = [[NSFileManager defaultManager] containerURLForSecurityApplicationGroupIdentifier:@"group.io.github.axiodl.Amuse.AudioGroups"];
|
m_groupURL = [[NSFileManager defaultManager] containerURLForSecurityApplicationGroupIdentifier:@"group.com.axiodl.Amuse.AudioGroups"];
|
||||||
if (!m_groupURL)
|
if (!m_groupURL)
|
||||||
return nil;
|
return nil;
|
||||||
[NSFileCoordinator addFilePresenter:self];
|
[NSFileCoordinator addFilePresenter:self];
|
||||||
|
|||||||
@@ -27,12 +27,10 @@ namespace amuse
|
|||||||
class AudioUnitBackendVoiceAllocator : public BooBackendVoiceAllocator
|
class AudioUnitBackendVoiceAllocator : public BooBackendVoiceAllocator
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
AudioUnitBackendVoiceAllocator(boo::IAudioVoiceEngine& booEngine)
|
AudioUnitBackendVoiceAllocator(boo::IAudioVoiceEngine& booEngine) : BooBackendVoiceAllocator(booEngine) {}
|
||||||
: BooBackendVoiceAllocator(booEngine) {}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
void RegisterAudioUnit();
|
void RegisterAudioUnit();
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@interface AmuseAudioUnit : AUAudioUnit <AudioGroupClient>
|
@interface AmuseAudioUnit : AUAudioUnit <AudioGroupClient>
|
||||||
|
|||||||
@@ -113,10 +113,12 @@ struct AudioUnitVoiceEngine : boo::BaseAudioVoiceEngine
|
|||||||
m_mixInfo.m_sampleRate = sampleRate;
|
m_mixInfo.m_sampleRate = sampleRate;
|
||||||
_buildAudioRenderClient();
|
_buildAudioRenderClient();
|
||||||
|
|
||||||
for (boo::AudioVoice* vox : m_activeVoices)
|
if (m_voiceHead)
|
||||||
vox->_resetSampleRate(vox->m_sampleRateIn);
|
for (boo::AudioVoice& vox : *m_voiceHead)
|
||||||
for (boo::AudioSubmix* smx : m_activeSubmixes)
|
vox._resetSampleRate(vox.m_sampleRateIn);
|
||||||
smx->_resetOutputSampleRate();
|
if (m_submixHead)
|
||||||
|
for (boo::AudioSubmix& smx : *m_submixHead)
|
||||||
|
smx._resetOutputSampleRate();
|
||||||
}
|
}
|
||||||
|
|
||||||
void pumpAndMixVoices()
|
void pumpAndMixVoices()
|
||||||
@@ -281,7 +283,7 @@ struct AudioUnitVoiceEngine : boo::BaseAudioVoiceEngine
|
|||||||
/* Output buffers */
|
/* Output buffers */
|
||||||
voxEngine.m_renderFrames = frameCount;
|
voxEngine.m_renderFrames = frameCount;
|
||||||
voxEngine.m_outputData = outputData;
|
voxEngine.m_outputData = outputData;
|
||||||
amuseEngine.pumpEngine();
|
voxEngine.pumpAndMixVoices();
|
||||||
return noErr;
|
return noErr;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
if (APPLE AND (NOT CMAKE_OSX_DEPLOYMENT_TARGET OR CMAKE_OSX_DEPLOYMENT_TARGET VERSION_GREATER 10.10))
|
if (APPLE AND (NOT CMAKE_OSX_DEPLOYMENT_TARGET OR CMAKE_OSX_DEPLOYMENT_TARGET VERSION_GREATER 10.10))
|
||||||
set(APPLE_DEV_ID "" CACHE STRING "Mac Developer ID string 'Mac Developer: John Smith (XXXXXXXXXX)'")
|
set(APPLE_DEV_ID "" CACHE STRING "Mac Developer ID string 'Mac Developer: John Smith (XXXXXXXXXX)'")
|
||||||
set(APPLE_TEAM_ID "" CACHE STRING "Team ID string provisioned within Xcode / Apple's portal")
|
set(APPLE_TEAM_ID "" CACHE STRING "Team ID string provisioned within Xcode / Apple's portal")
|
||||||
|
if (APPLE_DEV_ID AND APPLE_TEAM_ID)
|
||||||
find_library(AVFOUNDATION_LIBRARY AVFoundation)
|
find_library(AVFOUNDATION_LIBRARY AVFoundation)
|
||||||
find_library(AUDIOUNIT_LIBRARY AudioUnit)
|
find_library(AUDIOUNIT_LIBRARY AudioUnit)
|
||||||
find_library(COREAUDIOKIT_LIBRARY CoreAudioKit)
|
find_library(COREAUDIOKIT_LIBRARY CoreAudioKit)
|
||||||
@@ -34,7 +35,7 @@ if (APPLE AND (NOT CMAKE_OSX_DEPLOYMENT_TARGET OR CMAKE_OSX_DEPLOYMENT_TARGET VE
|
|||||||
AudioGroupFilePresenter.hpp AudioGroupFilePresenter.mm
|
AudioGroupFilePresenter.hpp AudioGroupFilePresenter.mm
|
||||||
AudioUnitViewController.nib)
|
AudioUnitViewController.nib)
|
||||||
|
|
||||||
set(APPLE_BUNDLE_ID "io.github.axiodl.Amuse.AudioUnit")
|
set(APPLE_BUNDLE_ID "com.axiodl.Amuse.AudioUnit")
|
||||||
configure_file(${CMAKE_CURRENT_SOURCE_DIR}/AmuseExtension.entitlements.in
|
configure_file(${CMAKE_CURRENT_SOURCE_DIR}/AmuseExtension.entitlements.in
|
||||||
${CMAKE_CURRENT_BINARY_DIR}/AmuseExtension.entitlements)
|
${CMAKE_CURRENT_BINARY_DIR}/AmuseExtension.entitlements)
|
||||||
|
|
||||||
@@ -66,9 +67,9 @@ if (APPLE AND (NOT CMAKE_OSX_DEPLOYMENT_TARGET OR CMAKE_OSX_DEPLOYMENT_TARGET VE
|
|||||||
AmuseContainingApp.mm AudioGroupFilePresenter.mm
|
AmuseContainingApp.mm AudioGroupFilePresenter.mm
|
||||||
PROPERTIES COMPILE_FLAGS -fobjc-arc)
|
PROPERTIES COMPILE_FLAGS -fobjc-arc)
|
||||||
target_link_libraries(amuse-au-container amuse boo soxr ${AUDIOUNIT_LIBRARY} ${COREAUDIOKIT_LIBRARY}
|
target_link_libraries(amuse-au-container amuse boo soxr ${AUDIOUNIT_LIBRARY} ${COREAUDIOKIT_LIBRARY}
|
||||||
${AVFOUNDATION_LIBRARY} ${ZLIB_LIBRARIES} ${BOO_SYS_LIBS} logvisor athena-core)
|
${AVFOUNDATION_LIBRARY} ${ZLIB_LIBRARIES} ${LZO_LIB} ${BOO_SYS_LIBS} logvisor athena-core)
|
||||||
|
|
||||||
set(APPLE_BUNDLE_ID "io.github.axiodl.Amuse")
|
set(APPLE_BUNDLE_ID "com.axiodl.Amuse")
|
||||||
configure_file(${CMAKE_CURRENT_SOURCE_DIR}/AmuseContainer.entitlements.in
|
configure_file(${CMAKE_CURRENT_SOURCE_DIR}/AmuseContainer.entitlements.in
|
||||||
${CMAKE_CURRENT_BINARY_DIR}/AmuseContainer.entitlements)
|
${CMAKE_CURRENT_BINARY_DIR}/AmuseContainer.entitlements)
|
||||||
|
|
||||||
@@ -103,7 +104,10 @@ if (APPLE AND (NOT CMAKE_OSX_DEPLOYMENT_TARGET OR CMAKE_OSX_DEPLOYMENT_TARGET VE
|
|||||||
)
|
)
|
||||||
|
|
||||||
else()
|
else()
|
||||||
message(WARNING "Unable to find developer provision profile; skipping Amuse-AU")
|
message(WARNING "Unable to find developer provisioning profile; skipping Amuse-AU")
|
||||||
endif()
|
endif()
|
||||||
endif()
|
endif()
|
||||||
|
else()
|
||||||
|
message(WARNING "APPLE_DEV_ID and/or APPLE_TEAM_ID not set; skipping Amuse-AU")
|
||||||
|
endif()
|
||||||
endif()
|
endif()
|
||||||
|
|||||||
@@ -20,7 +20,7 @@
|
|||||||
<key>CFBundleIconFile</key>
|
<key>CFBundleIconFile</key>
|
||||||
<string></string>
|
<string></string>
|
||||||
<key>CFBundleIdentifier</key>
|
<key>CFBundleIdentifier</key>
|
||||||
<string>io.github.axiodl.Amuse</string>
|
<string>com.axiodl.Amuse</string>
|
||||||
<key>CFBundleInfoDictionaryVersion</key>
|
<key>CFBundleInfoDictionaryVersion</key>
|
||||||
<string>6.0</string>
|
<string>6.0</string>
|
||||||
<key>CFBundleName</key>
|
<key>CFBundleName</key>
|
||||||
|
|||||||
@@ -9,7 +9,7 @@
|
|||||||
<key>CFBundleExecutable</key>
|
<key>CFBundleExecutable</key>
|
||||||
<string>amuse-au</string>
|
<string>amuse-au</string>
|
||||||
<key>CFBundleIdentifier</key>
|
<key>CFBundleIdentifier</key>
|
||||||
<string>io.github.axiodl.Amuse.AudioUnit</string>
|
<string>com.axiodl.Amuse.AudioUnit</string>
|
||||||
<key>CFBundleInfoDictionaryVersion</key>
|
<key>CFBundleInfoDictionaryVersion</key>
|
||||||
<string>6.0</string>
|
<string>6.0</string>
|
||||||
<key>CFBundleName</key>
|
<key>CFBundleName</key>
|
||||||
|
|||||||
@@ -1,9 +1,25 @@
|
|||||||
|
cmake_minimum_required(VERSION 3.10 FATAL_ERROR) # because of c++17
|
||||||
|
|
||||||
project(amuse)
|
project(amuse)
|
||||||
|
|
||||||
if(EXISTS boo)
|
set(CMAKE_CXX_STANDARD 17)
|
||||||
add_subdirectory(boo)
|
set(CMAKE_CXX_STANDARD_REQUIRED ON)
|
||||||
|
|
||||||
|
if(NOT MSVC)
|
||||||
|
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wno-narrowing")
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
|
if(EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/boo AND EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/athena)
|
||||||
|
message(STATUS "Preparing standalone build")
|
||||||
|
add_subdirectory(boo)
|
||||||
|
add_subdirectory(athena)
|
||||||
|
include_directories(athena/include)
|
||||||
|
endif()
|
||||||
|
|
||||||
|
atdna(atdna_AudioGroupPool.cpp include/amuse/AudioGroupPool.hpp)
|
||||||
|
atdna(atdna_AudioGroupProject.cpp include/amuse/AudioGroupProject.hpp)
|
||||||
|
atdna(atdna_AudioGroupSampleDirectory.cpp include/amuse/AudioGroupSampleDirectory.hpp)
|
||||||
|
|
||||||
set(SOURCES
|
set(SOURCES
|
||||||
lib/AudioGroup.cpp
|
lib/AudioGroup.cpp
|
||||||
lib/AudioGroupData.cpp
|
lib/AudioGroupData.cpp
|
||||||
@@ -20,16 +36,19 @@ set(SOURCES
|
|||||||
lib/SongConverter.cpp
|
lib/SongConverter.cpp
|
||||||
lib/SongState.cpp
|
lib/SongState.cpp
|
||||||
lib/Voice.cpp
|
lib/Voice.cpp
|
||||||
lib/VolumeLUT.cpp
|
|
||||||
lib/Submix.cpp
|
lib/Submix.cpp
|
||||||
lib/EffectBase.cpp
|
lib/Studio.cpp
|
||||||
lib/EffectReverb.cpp
|
lib/EffectReverb.cpp
|
||||||
lib/EffectChorus.cpp
|
lib/EffectChorus.cpp
|
||||||
lib/EffectDelay.cpp
|
lib/EffectDelay.cpp
|
||||||
lib/SurroundProfiles.cpp
|
|
||||||
lib/ContainerRegistry.cpp
|
lib/ContainerRegistry.cpp
|
||||||
lib/DSPCodec.c
|
lib/Common.cpp
|
||||||
lib/N64MusyXCodec.c)
|
lib/DSPCodec.cpp
|
||||||
|
lib/N64MusyXCodec.cpp
|
||||||
|
lib/VolumeTable.cpp
|
||||||
|
atdna_AudioGroupPool.cpp
|
||||||
|
atdna_AudioGroupProject.cpp
|
||||||
|
atdna_AudioGroupSampleDirectory.cpp)
|
||||||
|
|
||||||
set(HEADERS
|
set(HEADERS
|
||||||
include/amuse/AudioGroup.hpp
|
include/amuse/AudioGroup.hpp
|
||||||
@@ -49,6 +68,7 @@ set(HEADERS
|
|||||||
include/amuse/SongState.hpp
|
include/amuse/SongState.hpp
|
||||||
include/amuse/Voice.hpp
|
include/amuse/Voice.hpp
|
||||||
include/amuse/Submix.hpp
|
include/amuse/Submix.hpp
|
||||||
|
include/amuse/Studio.hpp
|
||||||
include/amuse/IBackendSubmix.hpp
|
include/amuse/IBackendSubmix.hpp
|
||||||
include/amuse/IBackendVoice.hpp
|
include/amuse/IBackendVoice.hpp
|
||||||
include/amuse/IBackendVoiceAllocator.hpp
|
include/amuse/IBackendVoiceAllocator.hpp
|
||||||
@@ -56,17 +76,17 @@ set(HEADERS
|
|||||||
include/amuse/EffectReverb.hpp
|
include/amuse/EffectReverb.hpp
|
||||||
include/amuse/EffectChorus.hpp
|
include/amuse/EffectChorus.hpp
|
||||||
include/amuse/EffectDelay.hpp
|
include/amuse/EffectDelay.hpp
|
||||||
include/amuse/SurroundProfiles.hpp
|
|
||||||
include/amuse/ContainerRegistry.hpp
|
include/amuse/ContainerRegistry.hpp
|
||||||
include/amuse/Common.hpp
|
include/amuse/Common.hpp
|
||||||
include/amuse/amuse.hpp
|
include/amuse/amuse.hpp
|
||||||
include/amuse/DSPCodec.h
|
include/amuse/DSPCodec.hpp
|
||||||
include/amuse/N64MusyXCodec.h)
|
include/amuse/N64MusyXCodec.hpp
|
||||||
|
include/amuse/VolumeTable.hpp)
|
||||||
|
|
||||||
unset(EXTRAS)
|
unset(EXTRAS)
|
||||||
if(TARGET boo)
|
if(TARGET boo)
|
||||||
include_directories(${BOO_INCLUDE_DIR} ${BOO_INCLUDE_DIR}/../lib ${BOO_INCLUDE_DIR}/../soxr/src
|
include_directories(${BOO_INCLUDE_DIR} ${BOO_INCLUDE_DIR}/../lib ${BOO_INCLUDE_DIR}/../soxr/src
|
||||||
${LOGVISOR_INCLUDE_DIR} ${ATHENA_INCLUDE_DIR} ${ZLIB_INCLUDE_DIR})
|
${LOGVISOR_INCLUDE_DIR} ${ATHENA_INCLUDE_DIR} ${ZLIB_INCLUDE_DIR} ${LZO_INCLUDE_DIR})
|
||||||
list(APPEND EXTRAS lib/BooBackend.cpp include/amuse/BooBackend.hpp)
|
list(APPEND EXTRAS lib/BooBackend.cpp include/amuse/BooBackend.hpp)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
@@ -77,8 +97,15 @@ add_library(amuse
|
|||||||
${SOURCES}
|
${SOURCES}
|
||||||
${HEADERS}
|
${HEADERS}
|
||||||
${EXTRAS})
|
${EXTRAS})
|
||||||
|
if(COMMAND add_sanitizers)
|
||||||
|
add_sanitizers(amuse)
|
||||||
|
endif()
|
||||||
|
if(COMMAND cotire)
|
||||||
|
set_target_properties(amuse PROPERTIES COTIRE_ADD_UNITY_BUILD FALSE)
|
||||||
|
cotire(amuse)
|
||||||
|
endif()
|
||||||
|
|
||||||
if(TARGET boo)
|
if(TARGET boo AND NOT WINDOWS_STORE)
|
||||||
# AudioUnit Target (OS X only)
|
# AudioUnit Target (OS X only)
|
||||||
add_subdirectory(AudioUnit)
|
add_subdirectory(AudioUnit)
|
||||||
|
|
||||||
@@ -89,9 +116,28 @@ if(TARGET boo)
|
|||||||
|
|
||||||
# Player
|
# Player
|
||||||
add_executable(amuseplay WIN32 driver/amuseplay.cpp)
|
add_executable(amuseplay WIN32 driver/amuseplay.cpp)
|
||||||
target_link_libraries(amuseplay amuse boo ${BOO_SYS_LIBS} logvisor athena-core ${ZLIB_LIBRARIES})
|
target_link_libraries(amuseplay amuse boo ${BOO_SYS_LIBS} logvisor athena-core athena-libyaml ${ZLIB_LIBRARIES} ${LZO_LIB})
|
||||||
|
|
||||||
# Converter
|
# Converter
|
||||||
add_executable(amuseconv driver/amuseconv.cpp)
|
add_executable(amuseconv driver/amuseconv.cpp)
|
||||||
target_link_libraries(amuseconv amuse ${BOO_SYS_LIBS} logvisor athena-core ${ZLIB_LIBRARIES})
|
target_link_libraries(amuseconv amuse boo ${BOO_SYS_LIBS} logvisor athena-core athena-libyaml ${ZLIB_LIBRARIES} ${LZO_LIB})
|
||||||
|
|
||||||
|
# Renderer
|
||||||
|
add_executable(amuserender driver/amuserender.cpp)
|
||||||
|
target_link_libraries(amuserender amuse boo ${BOO_SYS_LIBS} logvisor athena-core athena-libyaml ${ZLIB_LIBRARIES} ${LZO_LIB})
|
||||||
|
|
||||||
|
if(COMMAND add_sanitizers)
|
||||||
|
add_sanitizers(amuseplay)
|
||||||
|
add_sanitizers(amuseconv)
|
||||||
|
add_sanitizers(amuserender)
|
||||||
|
endif()
|
||||||
|
|
||||||
|
# Editor
|
||||||
|
find_package(Qt5Widgets)
|
||||||
|
if (Qt5Widgets_FOUND)
|
||||||
|
message(STATUS "Qt5 found, amuse-gui will be built")
|
||||||
|
add_subdirectory(Editor)
|
||||||
|
else()
|
||||||
|
message(STATUS "Qt5 not found, amuse-gui will not be built")
|
||||||
|
endif()
|
||||||
endif()
|
endif()
|
||||||
|
|||||||
1127
Editor/ADSREditor.cpp
Normal file
84
Editor/ADSREditor.hpp
Normal file
@@ -0,0 +1,84 @@
|
|||||||
|
#ifndef AMUSE_ADSR_EDITOR_HPP
|
||||||
|
#define AMUSE_ADSR_EDITOR_HPP
|
||||||
|
|
||||||
|
#include "EditorWidget.hpp"
|
||||||
|
#include <QFrame>
|
||||||
|
#include <QSpinBox>
|
||||||
|
#include <QDoubleSpinBox>
|
||||||
|
#include <QCheckBox>
|
||||||
|
#include <QLabel>
|
||||||
|
#include <QStaticText>
|
||||||
|
|
||||||
|
class ADSREditor;
|
||||||
|
|
||||||
|
class ADSRView : public QWidget
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
friend class ADSRControls;
|
||||||
|
amuse::ObjToken<ProjectModel::ADSRNode> m_node;
|
||||||
|
QFont m_gridFont;
|
||||||
|
QStaticText m_percentTexts[11];
|
||||||
|
std::vector<QStaticText> m_timeTexts;
|
||||||
|
int m_dragPoint = -1;
|
||||||
|
uint64_t m_cycleIdx = 0;
|
||||||
|
ADSREditor* getEditor() const;
|
||||||
|
public:
|
||||||
|
explicit ADSRView(QWidget* parent = Q_NULLPTR);
|
||||||
|
void loadData(ProjectModel::ADSRNode* node);
|
||||||
|
void unloadData();
|
||||||
|
ProjectModel::INode* currentNode() const;
|
||||||
|
|
||||||
|
void paintEvent(QPaintEvent* ev);
|
||||||
|
void mousePressEvent(QMouseEvent* ev);
|
||||||
|
void mouseReleaseEvent(QMouseEvent* ev);
|
||||||
|
void mouseMoveEvent(QMouseEvent* ev);
|
||||||
|
};
|
||||||
|
|
||||||
|
class ADSRControls : public QFrame
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
friend class ADSRView;
|
||||||
|
QDoubleSpinBox* m_attack;
|
||||||
|
QDoubleSpinBox* m_decay;
|
||||||
|
QDoubleSpinBox* m_sustain;
|
||||||
|
QDoubleSpinBox* m_release;
|
||||||
|
QCheckBox* m_dls;
|
||||||
|
QLabel* m_velToAttackLab;
|
||||||
|
QDoubleSpinBox* m_velToAttack;
|
||||||
|
QLabel* m_keyToDecayLab;
|
||||||
|
QDoubleSpinBox* m_keyToDecay;
|
||||||
|
bool m_enableUpdate = true;
|
||||||
|
ADSREditor* getEditor() const;
|
||||||
|
void setAttackAndDecay(double attack, double decay, uint64_t cycleCount);
|
||||||
|
void setDecayAndSustain(double decay, double sustain, uint64_t cycleCount);
|
||||||
|
void setRelease(double release, uint64_t cycleCount);
|
||||||
|
public:
|
||||||
|
explicit ADSRControls(QWidget* parent = Q_NULLPTR);
|
||||||
|
void loadData();
|
||||||
|
void unloadData();
|
||||||
|
public slots:
|
||||||
|
void attackChanged(double val);
|
||||||
|
void decayChanged(double val);
|
||||||
|
void sustainChanged(double val);
|
||||||
|
void releaseChanged(double val);
|
||||||
|
void dlsStateChanged(int state);
|
||||||
|
void velToAttackChanged(double val);
|
||||||
|
void keyToDecayChanged(double val);
|
||||||
|
};
|
||||||
|
|
||||||
|
class ADSREditor : public EditorWidget
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
friend class ADSRView;
|
||||||
|
friend class ADSRControls;
|
||||||
|
ADSRView* m_adsrView;
|
||||||
|
ADSRControls* m_controls;
|
||||||
|
public:
|
||||||
|
explicit ADSREditor(QWidget* parent = Q_NULLPTR);
|
||||||
|
bool loadData(ProjectModel::ADSRNode* node);
|
||||||
|
void unloadData();
|
||||||
|
ProjectModel::INode* currentNode() const;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
#endif //AMUSE_ADSR_EDITOR_HPP
|
||||||
87
Editor/CMakeLists.txt
Normal file
@@ -0,0 +1,87 @@
|
|||||||
|
cmake_minimum_required(VERSION 3.10)
|
||||||
|
|
||||||
|
set(CMAKE_INCLUDE_CURRENT_DIR ON)
|
||||||
|
|
||||||
|
find_package(Qt5Widgets REQUIRED)
|
||||||
|
find_package(Qt5Network REQUIRED)
|
||||||
|
find_package(Qt5Xml REQUIRED)
|
||||||
|
find_package(Qt5Svg REQUIRED)
|
||||||
|
find_package(Qt5Qml REQUIRED)
|
||||||
|
find_package(Qt5LinguistTools REQUIRED)
|
||||||
|
|
||||||
|
if(WIN32)
|
||||||
|
list(APPEND PLAT_SRCS platforms/win/amuse-gui.rc platforms/win/amuse-gui.manifest)
|
||||||
|
elseif(APPLE)
|
||||||
|
list(APPEND PLAT_SRCS platforms/mac/mainicon.icns MacOSExtras.mm)
|
||||||
|
set_source_files_properties(platforms/mac/mainicon.icns PROPERTIES
|
||||||
|
MACOSX_PACKAGE_LOCATION Resources)
|
||||||
|
endif()
|
||||||
|
|
||||||
|
add_subdirectory(platforms/freedesktop)
|
||||||
|
declare_qticon_target()
|
||||||
|
list(APPEND PLAT_SRCS mainicon_qt.cpp)
|
||||||
|
|
||||||
|
configure_file(resources/translation_res.qrc translation_res.qrc @ONLY)
|
||||||
|
set(TRANSLATIONS
|
||||||
|
resources/lang_de.ts)
|
||||||
|
QT5_CREATE_TRANSLATION(QM_FILES ${CMAKE_CURRENT_SOURCE_DIR} ${CMAKE_CURRENT_SOURCE_DIR}/../lib ${TRANSLATIONS})
|
||||||
|
|
||||||
|
QT5_ADD_RESOURCES(qrc_resources.cpp resources/resources.qrc)
|
||||||
|
QT5_ADD_RESOURCES(qrc_translation_res.cpp ${CMAKE_CURRENT_BINARY_DIR}/translation_res.qrc OPTIONS -no-compress)
|
||||||
|
|
||||||
|
QT5_WRAP_UI(MAIN_WINDOW_UI MainWindow.ui)
|
||||||
|
|
||||||
|
QT5_WRAP_CPP(AMUSE_MOC
|
||||||
|
Common.hpp
|
||||||
|
MainWindow.hpp
|
||||||
|
KeyboardWidget.hpp
|
||||||
|
StatusBarWidget.hpp
|
||||||
|
ProjectModel.hpp
|
||||||
|
EditorWidget.hpp
|
||||||
|
SoundMacroEditor.hpp
|
||||||
|
ADSREditor.hpp
|
||||||
|
CurveEditor.hpp
|
||||||
|
KeymapEditor.hpp
|
||||||
|
LayersEditor.hpp
|
||||||
|
SampleEditor.hpp
|
||||||
|
SoundGroupEditor.hpp
|
||||||
|
SongGroupEditor.hpp
|
||||||
|
NewSoundMacroDialog.hpp
|
||||||
|
StudioSetupWidget.hpp)
|
||||||
|
|
||||||
|
add_executable(amuse-gui WIN32 MACOSX_BUNDLE
|
||||||
|
Common.hpp Common.cpp
|
||||||
|
MainWindow.ui ${MAIN_WINDOW_UI} MainWindow.hpp MainWindow.cpp
|
||||||
|
KeyboardWidget.hpp KeyboardWidget.cpp
|
||||||
|
StatusBarWidget.hpp StatusBarWidget.cpp
|
||||||
|
ProjectModel.hpp ProjectModel.cpp
|
||||||
|
EditorWidget.hpp EditorWidget.cpp
|
||||||
|
SoundMacroEditor.hpp SoundMacroEditor.cpp
|
||||||
|
ADSREditor.hpp ADSREditor.cpp
|
||||||
|
CurveEditor.hpp CurveEditor.cpp
|
||||||
|
KeymapEditor.hpp KeymapEditor.cpp
|
||||||
|
LayersEditor.hpp LayersEditor.cpp
|
||||||
|
SampleEditor.hpp SampleEditor.cpp
|
||||||
|
SoundGroupEditor.hpp SoundGroupEditor.cpp
|
||||||
|
SongGroupEditor.hpp SongGroupEditor.cpp
|
||||||
|
NewSoundMacroDialog.hpp NewSoundMacroDialog.cpp
|
||||||
|
StudioSetupWidget.hpp StudioSetupWidget.cpp
|
||||||
|
MIDIReader.hpp MIDIReader.cpp
|
||||||
|
resources/resources.qrc qrc_resources.cpp
|
||||||
|
${QM_FILES} qrc_translation_res.cpp
|
||||||
|
${AMUSE_MOC} ${PLAT_SRCS}
|
||||||
|
main.cpp)
|
||||||
|
if(COMMAND add_sanitizers)
|
||||||
|
add_sanitizers(amuse-gui)
|
||||||
|
endif()
|
||||||
|
|
||||||
|
set_target_properties(amuse-gui PROPERTIES
|
||||||
|
MACOSX_BUNDLE_INFO_PLIST "${CMAKE_CURRENT_SOURCE_DIR}/platforms/mac/Info.plist")
|
||||||
|
|
||||||
|
target_link_libraries(amuse-gui ${PLAT_LIBS}
|
||||||
|
${Qt5Widgets_LIBRARIES}
|
||||||
|
${Qt5Network_LIBRARIES}
|
||||||
|
${Qt5Xml_LIBRARIES}
|
||||||
|
${Qt5Svg_LIBRARIES}
|
||||||
|
${Qt5Qml_LIBRARIES}
|
||||||
|
amuse boo ${BOO_SYS_LIBS} logvisor athena-core athena-libyaml xxhash ${ZLIB_LIBRARIES} ${LZO_LIB})
|
||||||
108
Editor/Common.cpp
Normal file
@@ -0,0 +1,108 @@
|
|||||||
|
#include "Common.hpp"
|
||||||
|
#include "MainWindow.hpp"
|
||||||
|
#include <QMessageBox>
|
||||||
|
#include <QObject>
|
||||||
|
#include <QProcess>
|
||||||
|
|
||||||
|
boo::SystemString QStringToSysString(const QString& str)
|
||||||
|
{
|
||||||
|
#ifdef _WIN32
|
||||||
|
return (wchar_t*)str.utf16();
|
||||||
|
#else
|
||||||
|
return str.toUtf8().toStdString();
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
QString SysStringToQString(const boo::SystemString& str)
|
||||||
|
{
|
||||||
|
#ifdef _WIN32
|
||||||
|
return QString::fromStdWString(str);
|
||||||
|
#else
|
||||||
|
return QString::fromStdString(str);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
bool MkPath(const QString& path, UIMessenger& messenger)
|
||||||
|
{
|
||||||
|
QFileInfo fInfo(path);
|
||||||
|
return MkPath(fInfo.dir(), fInfo.fileName(), messenger);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool MkPath(const QDir& dir, const QString& file, UIMessenger& messenger)
|
||||||
|
{
|
||||||
|
if (!dir.mkpath(file))
|
||||||
|
{
|
||||||
|
QString msg = QString(MainWindow::tr("A directory at '%1/%2' could not be created.")).arg(dir.path()).arg(file);
|
||||||
|
messenger.critical(MainWindow::tr("Unable to create directory"), msg);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ShowInGraphicalShell(QWidget* parent, const QString& pathIn)
|
||||||
|
{
|
||||||
|
const QFileInfo fileInfo(pathIn);
|
||||||
|
// Mac, Windows support folder or file.
|
||||||
|
#if defined(Q_OS_WIN)
|
||||||
|
QString paths = QProcessEnvironment::systemEnvironment().value(QStringLiteral("Path"));
|
||||||
|
QString explorer;
|
||||||
|
for (QString path : paths.split(QStringLiteral(";")))
|
||||||
|
{
|
||||||
|
QFileInfo finfo(QDir(path), QStringLiteral("explorer.exe"));
|
||||||
|
if (finfo.exists())
|
||||||
|
{
|
||||||
|
explorer = finfo.filePath();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (explorer.isEmpty()) {
|
||||||
|
QMessageBox::warning(parent,
|
||||||
|
MainWindow::tr("Launching Windows Explorer Failed"),
|
||||||
|
MainWindow::tr("Could not find explorer.exe in path to launch Windows Explorer."));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
QStringList param;
|
||||||
|
if (!fileInfo.isDir())
|
||||||
|
param += QLatin1String("/select,");
|
||||||
|
param += QDir::toNativeSeparators(fileInfo.canonicalFilePath());
|
||||||
|
QProcess::startDetached(explorer, param);
|
||||||
|
#elif defined(Q_OS_MAC)
|
||||||
|
QStringList scriptArgs;
|
||||||
|
scriptArgs << QLatin1String("-e")
|
||||||
|
<< QString::fromLatin1("tell application \"Finder\" to reveal POSIX file \"%1\"")
|
||||||
|
.arg(fileInfo.canonicalFilePath());
|
||||||
|
QProcess::execute(QLatin1String("/usr/bin/osascript"), scriptArgs);
|
||||||
|
scriptArgs.clear();
|
||||||
|
scriptArgs << QLatin1String("-e")
|
||||||
|
<< QLatin1String("tell application \"Finder\" to activate");
|
||||||
|
QProcess::execute(QLatin1String("/usr/bin/osascript"), scriptArgs);
|
||||||
|
#else
|
||||||
|
// we cannot select a file here, because no file browser really supports it...
|
||||||
|
const QString folder = fileInfo.isDir() ? fileInfo.absoluteFilePath() : fileInfo.filePath();
|
||||||
|
QProcess browserProc;
|
||||||
|
const QString browserArgs = QStringLiteral("xdg-open \"%1\"").arg(QFileInfo(folder).path());
|
||||||
|
browserProc.startDetached(browserArgs);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
QString ShowInGraphicalShellString()
|
||||||
|
{
|
||||||
|
#if defined(Q_OS_WIN)
|
||||||
|
return MainWindow::tr("Show in Explorer");
|
||||||
|
#elif defined(Q_OS_MAC)
|
||||||
|
return MainWindow::tr("Show in Finder");
|
||||||
|
#else
|
||||||
|
return MainWindow::tr("Show in Browser");
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
QTransform RectToRect(const QRectF& from, const QRectF& to)
|
||||||
|
{
|
||||||
|
QPolygonF orig(from);
|
||||||
|
orig.pop_back();
|
||||||
|
QPolygonF resize(to);
|
||||||
|
resize.pop_back();
|
||||||
|
QTransform ret;
|
||||||
|
QTransform::quadToQuad(orig, resize, ret);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
68
Editor/Common.hpp
Normal file
@@ -0,0 +1,68 @@
|
|||||||
|
#ifndef AMUSE_COMMON_HPP
|
||||||
|
#define AMUSE_COMMON_HPP
|
||||||
|
|
||||||
|
#include "boo/System.hpp"
|
||||||
|
#include <QString>
|
||||||
|
#include <QDir>
|
||||||
|
#include <QMessageBox>
|
||||||
|
|
||||||
|
class MainWindow;
|
||||||
|
extern MainWindow* g_MainWindow;
|
||||||
|
|
||||||
|
class UIMessenger : public QObject
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
public:
|
||||||
|
using QObject::QObject;
|
||||||
|
signals:
|
||||||
|
QMessageBox::StandardButton information(const QString &title,
|
||||||
|
const QString &text, QMessageBox::StandardButtons buttons = QMessageBox::Ok,
|
||||||
|
QMessageBox::StandardButton defaultButton = QMessageBox::NoButton);
|
||||||
|
int question(const QString &title,
|
||||||
|
const QString& text,
|
||||||
|
const QString& button0Text,
|
||||||
|
const QString& button1Text = QString(),
|
||||||
|
const QString& button2Text = QString(),
|
||||||
|
int defaultButtonNumber = 0,
|
||||||
|
int escapeButtonNumber = -1);
|
||||||
|
QMessageBox::StandardButton question(const QString &title,
|
||||||
|
const QString &text, QMessageBox::StandardButtons buttons =
|
||||||
|
QMessageBox::StandardButtons(QMessageBox::Yes | QMessageBox::No),
|
||||||
|
QMessageBox::StandardButton defaultButton = QMessageBox::NoButton);
|
||||||
|
QMessageBox::StandardButton warning(const QString &title,
|
||||||
|
const QString &text, QMessageBox::StandardButtons buttons = QMessageBox::Ok,
|
||||||
|
QMessageBox::StandardButton defaultButton = QMessageBox::NoButton);
|
||||||
|
QMessageBox::StandardButton critical(const QString &title,
|
||||||
|
const QString &text, QMessageBox::StandardButtons buttons = QMessageBox::Ok,
|
||||||
|
QMessageBox::StandardButton defaultButton = QMessageBox::NoButton);
|
||||||
|
};
|
||||||
|
|
||||||
|
boo::SystemString QStringToSysString(const QString& str);
|
||||||
|
QString SysStringToQString(const boo::SystemString& str);
|
||||||
|
|
||||||
|
bool MkPath(const QString& path, UIMessenger& messenger);
|
||||||
|
bool MkPath(const QDir& dir, const QString& file, UIMessenger& messenger);
|
||||||
|
|
||||||
|
void ShowInGraphicalShell(QWidget* parent, const QString& pathIn);
|
||||||
|
QString ShowInGraphicalShellString();
|
||||||
|
|
||||||
|
static QLatin1String StringViewToQString(std::string_view sv)
|
||||||
|
{
|
||||||
|
return QLatin1String(sv.data(), int(sv.size()));
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Used for generating transform matrices to map SVG coordinate space */
|
||||||
|
QTransform RectToRect(const QRectF& from, const QRectF& to);
|
||||||
|
|
||||||
|
namespace std
|
||||||
|
{
|
||||||
|
template<> struct hash<QString>
|
||||||
|
{
|
||||||
|
std::size_t operator()(const QString& s) const noexcept
|
||||||
|
{
|
||||||
|
return qHash(s);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif //AMUSE_COMMON_HPP
|
||||||
326
Editor/CurveEditor.cpp
Normal file
@@ -0,0 +1,326 @@
|
|||||||
|
#include "CurveEditor.hpp"
|
||||||
|
#include "MainWindow.hpp"
|
||||||
|
#include <QHBoxLayout>
|
||||||
|
#include <QGridLayout>
|
||||||
|
#include <QPainter>
|
||||||
|
#include <QMouseEvent>
|
||||||
|
#include <QJSValueIterator>
|
||||||
|
|
||||||
|
class CurveEditUndoCommand : public EditorUndoCommand
|
||||||
|
{
|
||||||
|
uint8_t m_redoData[128];
|
||||||
|
uint8_t m_undoData[128];
|
||||||
|
bool m_usedExpr;
|
||||||
|
bool m_undid = false;
|
||||||
|
public:
|
||||||
|
CurveEditUndoCommand(const uint8_t* redoData, bool usedExpr,
|
||||||
|
amuse::ObjToken<ProjectModel::CurveNode> node)
|
||||||
|
: EditorUndoCommand(node.get(), CurveControls::tr("Edit Curve")), m_usedExpr(usedExpr)
|
||||||
|
{
|
||||||
|
std::memcpy(m_redoData, redoData, 128);
|
||||||
|
}
|
||||||
|
void undo()
|
||||||
|
{
|
||||||
|
m_undid = true;
|
||||||
|
amuse::ITable& table = **m_node.cast<ProjectModel::CurveNode>()->m_obj;
|
||||||
|
if (table.Isa() == amuse::ITable::Type::Curve)
|
||||||
|
{
|
||||||
|
amuse::Curve& curve = static_cast<amuse::Curve&>(table);
|
||||||
|
curve.data.resize(128);
|
||||||
|
std::memcpy(curve.data.data(), m_undoData, 128);
|
||||||
|
}
|
||||||
|
EditorUndoCommand::undo();
|
||||||
|
}
|
||||||
|
void redo()
|
||||||
|
{
|
||||||
|
amuse::ITable& table = **m_node.cast<ProjectModel::CurveNode>()->m_obj;
|
||||||
|
if (table.Isa() == amuse::ITable::Type::Curve)
|
||||||
|
{
|
||||||
|
amuse::Curve& curve = static_cast<amuse::Curve&>(table);
|
||||||
|
curve.data.resize(128);
|
||||||
|
std::memcpy(m_undoData, curve.data.data(), 128);
|
||||||
|
std::memcpy(curve.data.data(), m_redoData, 128);
|
||||||
|
}
|
||||||
|
if (m_undid)
|
||||||
|
EditorUndoCommand::redo();
|
||||||
|
}
|
||||||
|
bool mergeWith(const QUndoCommand* other)
|
||||||
|
{
|
||||||
|
if (other->id() == id() && !m_usedExpr && !static_cast<const CurveEditUndoCommand*>(other)->m_usedExpr)
|
||||||
|
{
|
||||||
|
std::memcpy(m_redoData, static_cast<const CurveEditUndoCommand*>(other)->m_redoData, 128);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
int id() const { return int(Id::CurveEdit); }
|
||||||
|
};
|
||||||
|
|
||||||
|
CurveEditor* CurveView::getEditor() const
|
||||||
|
{
|
||||||
|
return qobject_cast<CurveEditor*>(parentWidget());
|
||||||
|
}
|
||||||
|
|
||||||
|
void CurveView::loadData(ProjectModel::CurveNode* node)
|
||||||
|
{
|
||||||
|
m_node = node;
|
||||||
|
}
|
||||||
|
|
||||||
|
void CurveView::unloadData()
|
||||||
|
{
|
||||||
|
m_node.reset();
|
||||||
|
}
|
||||||
|
|
||||||
|
ProjectModel::INode* CurveView::currentNode() const
|
||||||
|
{
|
||||||
|
return m_node.get();
|
||||||
|
}
|
||||||
|
|
||||||
|
void CurveView::paintEvent(QPaintEvent* ev)
|
||||||
|
{
|
||||||
|
if (!m_node)
|
||||||
|
return;
|
||||||
|
amuse::ITable& table = **m_node->m_obj;
|
||||||
|
if (table.Isa() != amuse::ITable::Type::Curve)
|
||||||
|
return;
|
||||||
|
amuse::Curve& curve = static_cast<amuse::Curve&>(table);
|
||||||
|
|
||||||
|
QPainter painter(this);
|
||||||
|
painter.setRenderHint(QPainter::Antialiasing);
|
||||||
|
|
||||||
|
qreal deviceRatio = devicePixelRatioF();
|
||||||
|
qreal penWidth = std::max(std::floor(deviceRatio), 1.0) / deviceRatio;
|
||||||
|
|
||||||
|
painter.setPen(QPen(QColor(127, 127, 127), penWidth));
|
||||||
|
painter.setFont(m_gridFont);
|
||||||
|
qreal yIncrement = (height() - 16.0) / 10.0;
|
||||||
|
for (int i = 0; i < 11; ++i)
|
||||||
|
{
|
||||||
|
qreal thisY = i * yIncrement;
|
||||||
|
qreal textY = thisY - (i == 0 ? 2.0 : (i == 10 ? 16.0 : 8.0));
|
||||||
|
painter.drawStaticText(QPointF(0.0, textY), m_percentTexts[i]);
|
||||||
|
painter.drawLine(QPointF(30.0, thisY), QPointF(width(), thisY));
|
||||||
|
}
|
||||||
|
|
||||||
|
qreal xIncrement = (width() - 30.0) / 10.0;
|
||||||
|
for (int i = 0; i < 11; ++i)
|
||||||
|
{
|
||||||
|
qreal thisX = i * xIncrement + 30.0;
|
||||||
|
qreal textX = thisX - (i == 10 ? 30.0 : 15.0);
|
||||||
|
painter.drawStaticText(QPointF(textX, height() - 16.0), m_percentTextsCenter[i]);
|
||||||
|
painter.drawLine(QPointF(thisX, 0.0), QPointF(thisX, height() - 16.0));
|
||||||
|
}
|
||||||
|
|
||||||
|
int i;
|
||||||
|
xIncrement = (width() - 30.0) / 127.0;
|
||||||
|
QPointF lastPt;
|
||||||
|
painter.setPen(QPen(Qt::white, penWidth * 3.0));
|
||||||
|
for (i = 0; i < curve.data.size(); ++i)
|
||||||
|
{
|
||||||
|
QPointF thisPt(i * xIncrement + 30.0, (height() - 16.0) - (height() - 16.0) * (curve.data[i] / 127.0));
|
||||||
|
if (i)
|
||||||
|
painter.drawLine(lastPt, thisPt);
|
||||||
|
lastPt = thisPt;
|
||||||
|
}
|
||||||
|
for (; i < 128; ++i)
|
||||||
|
{
|
||||||
|
QPointF thisPt(i * xIncrement + 30.0, height() - 16.0);
|
||||||
|
if (i)
|
||||||
|
painter.drawLine(lastPt, thisPt);
|
||||||
|
lastPt = thisPt;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void CurveView::mousePressEvent(QMouseEvent* ev)
|
||||||
|
{
|
||||||
|
mouseMoveEvent(ev);
|
||||||
|
}
|
||||||
|
|
||||||
|
void CurveView::mouseMoveEvent(QMouseEvent* ev)
|
||||||
|
{
|
||||||
|
CurveView* view = getEditor()->m_curveView;
|
||||||
|
amuse::ITable& table = **view->m_node->m_obj;
|
||||||
|
if (table.Isa() != amuse::ITable::Type::Curve)
|
||||||
|
return;
|
||||||
|
amuse::Curve& curve = static_cast<amuse::Curve&>(table);
|
||||||
|
|
||||||
|
qreal xIncrement = (width() - 30.0) / 127.0;
|
||||||
|
int idx = int(std::round((ev->localPos().x() - 30.0) / xIncrement));
|
||||||
|
if (idx < 0 || idx > 127)
|
||||||
|
return;
|
||||||
|
int val = 127 - amuse::clamp(0, int(std::round(ev->localPos().y() / (height() - 16.0) * 127.0)), 127);
|
||||||
|
|
||||||
|
curve.data.resize(128);
|
||||||
|
uint8_t newData[128];
|
||||||
|
std::memcpy(newData, curve.data.data(), 128);
|
||||||
|
newData[idx] = uint8_t(val);
|
||||||
|
|
||||||
|
g_MainWindow->pushUndoCommand(new CurveEditUndoCommand(newData, false, m_node));
|
||||||
|
update();
|
||||||
|
}
|
||||||
|
|
||||||
|
CurveView::CurveView(QWidget* parent)
|
||||||
|
: QWidget(parent)
|
||||||
|
{
|
||||||
|
for (int i = 0; i < 11; ++i)
|
||||||
|
{
|
||||||
|
m_percentTexts[i].setText(QStringLiteral("%1%").arg(100 - i * 10));
|
||||||
|
m_percentTexts[i].setTextOption(QTextOption(Qt::AlignVCenter | Qt::AlignRight));
|
||||||
|
m_percentTexts[i].setTextWidth(28.0);
|
||||||
|
m_percentTextsCenter[i].setText(QStringLiteral("%1%").arg(i * 10));
|
||||||
|
m_percentTextsCenter[i].setTextOption(QTextOption(Qt::AlignBaseline | Qt::AlignCenter));
|
||||||
|
m_percentTextsCenter[i].setTextWidth(28.0);
|
||||||
|
}
|
||||||
|
m_gridFont.setPointSize(8);
|
||||||
|
}
|
||||||
|
|
||||||
|
CurveEditor* CurveControls::getEditor() const
|
||||||
|
{
|
||||||
|
return qobject_cast<CurveEditor*>(parentWidget());
|
||||||
|
}
|
||||||
|
|
||||||
|
void CurveControls::loadData()
|
||||||
|
{
|
||||||
|
m_lineEdit->setDisabled(false);
|
||||||
|
m_setExpr->setDisabled(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
void CurveControls::unloadData()
|
||||||
|
{
|
||||||
|
m_lineEdit->setDisabled(true);
|
||||||
|
m_setExpr->setDisabled(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
void CurveControls::exprCommit()
|
||||||
|
{
|
||||||
|
CurveView* view = getEditor()->m_curveView;
|
||||||
|
amuse::ITable& table = **view->m_node->m_obj;
|
||||||
|
if (table.Isa() != amuse::ITable::Type::Curve)
|
||||||
|
return;
|
||||||
|
amuse::Curve& curve = static_cast<amuse::Curve&>(table);
|
||||||
|
|
||||||
|
QString progText = m_lineEdit->text();
|
||||||
|
curve.data.resize(128);
|
||||||
|
uint8_t newData[128];
|
||||||
|
std::memcpy(newData, curve.data.data(), 128);
|
||||||
|
bool notANumber = false;
|
||||||
|
for (int i = 0; i < 128; ++i)
|
||||||
|
{
|
||||||
|
m_engine.globalObject().setProperty(QStringLiteral("x"), i / 127.0);
|
||||||
|
QJSValue val = m_engine.evaluate(progText);
|
||||||
|
if (val.isError())
|
||||||
|
{
|
||||||
|
m_errLabel->setText(val.toString());
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
else if (val.isNumber())
|
||||||
|
{
|
||||||
|
newData[i] = uint8_t(amuse::clamp(0, int(std::round(val.toNumber() * 127.0)), 127));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
notANumber = true;
|
||||||
|
newData[i] = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (notANumber)
|
||||||
|
m_errLabel->setText(tr("Did not evaluate as a number"));
|
||||||
|
|
||||||
|
g_MainWindow->pushUndoCommand(new CurveEditUndoCommand(newData, true, view->m_node));
|
||||||
|
view->update();
|
||||||
|
}
|
||||||
|
|
||||||
|
void CurveControls::resizeEvent(QResizeEvent* ev)
|
||||||
|
{
|
||||||
|
m_errLabel->setGeometry(22, 78, width() - 44, 14);
|
||||||
|
}
|
||||||
|
|
||||||
|
CurveControls::CurveControls(QWidget* parent)
|
||||||
|
: QFrame(parent)
|
||||||
|
{
|
||||||
|
setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Fixed);
|
||||||
|
setFixedHeight(100);
|
||||||
|
setFrameShape(QFrame::StyledPanel);
|
||||||
|
setFrameShadow(QFrame::Sunken);
|
||||||
|
setBackgroundRole(QPalette::Base);
|
||||||
|
setAutoFillBackground(true);
|
||||||
|
|
||||||
|
QHBoxLayout* mainLayout = new QHBoxLayout;
|
||||||
|
|
||||||
|
QGridLayout* leftLayout = new QGridLayout;
|
||||||
|
|
||||||
|
leftLayout->addWidget(new QLabel(tr("Expression")), 0, 0);
|
||||||
|
m_lineEdit = new QLineEdit;
|
||||||
|
m_lineEdit->setDisabled(true);
|
||||||
|
QPalette palette = m_lineEdit->palette();
|
||||||
|
palette.setColor(QPalette::Base, palette.color(QPalette::Background));
|
||||||
|
m_lineEdit->setPalette(palette);
|
||||||
|
connect(m_lineEdit, SIGNAL(returnPressed()), this, SLOT(exprCommit()));
|
||||||
|
leftLayout->addWidget(m_lineEdit, 1, 0);
|
||||||
|
|
||||||
|
m_setExpr = new QPushButton(tr("Apply"));
|
||||||
|
m_setExpr->setDisabled(true);
|
||||||
|
connect(m_setExpr, SIGNAL(clicked(bool)), this, SLOT(exprCommit()));
|
||||||
|
leftLayout->addWidget(m_setExpr, 1, 1);
|
||||||
|
|
||||||
|
m_errLabel = new QLabel(this);
|
||||||
|
QFont font = m_errLabel->font();
|
||||||
|
font.setPointSize(8);
|
||||||
|
m_errLabel->setFont(font);
|
||||||
|
palette.setColor(QPalette::Text, Qt::red);
|
||||||
|
m_errLabel->setPalette(palette);
|
||||||
|
|
||||||
|
leftLayout->setColumnMinimumWidth(0, 500);
|
||||||
|
leftLayout->setColumnStretch(0, 1);
|
||||||
|
leftLayout->setColumnMinimumWidth(1, 75);
|
||||||
|
leftLayout->setColumnStretch(1, 0);
|
||||||
|
leftLayout->setRowMinimumHeight(0, 22);
|
||||||
|
leftLayout->setRowMinimumHeight(1, 37);
|
||||||
|
leftLayout->setContentsMargins(10, 6, 10, 14);
|
||||||
|
|
||||||
|
mainLayout->addLayout(leftLayout);
|
||||||
|
setLayout(mainLayout);
|
||||||
|
|
||||||
|
QJSValueIterator it(m_engine.globalObject().property(QStringLiteral("Math")));
|
||||||
|
QString docStr = tr("Expression interpreter mapping x:[0,1] to y:[0,1] with the following constants and functions available:\n");
|
||||||
|
bool needsComma = false;
|
||||||
|
while (it.hasNext())
|
||||||
|
{
|
||||||
|
it.next();
|
||||||
|
m_engine.globalObject().setProperty(it.name(), it.value());
|
||||||
|
if (needsComma)
|
||||||
|
docStr += QStringLiteral(", ");
|
||||||
|
needsComma = true;
|
||||||
|
docStr += it.name();
|
||||||
|
}
|
||||||
|
m_lineEdit->setToolTip(docStr);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool CurveEditor::loadData(ProjectModel::CurveNode* node)
|
||||||
|
{
|
||||||
|
m_curveView->loadData(node);
|
||||||
|
m_controls->loadData();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void CurveEditor::unloadData()
|
||||||
|
{
|
||||||
|
m_curveView->unloadData();
|
||||||
|
m_controls->unloadData();
|
||||||
|
}
|
||||||
|
|
||||||
|
ProjectModel::INode* CurveEditor::currentNode() const
|
||||||
|
{
|
||||||
|
return m_curveView->currentNode();
|
||||||
|
}
|
||||||
|
|
||||||
|
CurveEditor::CurveEditor(QWidget* parent)
|
||||||
|
: EditorWidget(parent), m_curveView(new CurveView), m_controls(new CurveControls)
|
||||||
|
{
|
||||||
|
QVBoxLayout* layout = new QVBoxLayout;
|
||||||
|
layout->setContentsMargins(QMargins());
|
||||||
|
layout->setSpacing(1);
|
||||||
|
layout->addWidget(m_curveView);
|
||||||
|
layout->addWidget(m_controls);
|
||||||
|
setLayout(layout);
|
||||||
|
}
|
||||||
66
Editor/CurveEditor.hpp
Normal file
@@ -0,0 +1,66 @@
|
|||||||
|
#ifndef AMUSE_CURVE_EDITOR_HPP
|
||||||
|
#define AMUSE_CURVE_EDITOR_HPP
|
||||||
|
|
||||||
|
#include "EditorWidget.hpp"
|
||||||
|
#include <QFrame>
|
||||||
|
#include <QLabel>
|
||||||
|
#include <QStaticText>
|
||||||
|
#include <QLineEdit>
|
||||||
|
#include <QPushButton>
|
||||||
|
#include <QJSEngine>
|
||||||
|
|
||||||
|
class CurveEditor;
|
||||||
|
|
||||||
|
class CurveView : public QWidget
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
friend class CurveControls;
|
||||||
|
amuse::ObjToken<ProjectModel::CurveNode> m_node;
|
||||||
|
QFont m_gridFont;
|
||||||
|
QStaticText m_percentTexts[11];
|
||||||
|
QStaticText m_percentTextsCenter[11];
|
||||||
|
CurveEditor* getEditor() const;
|
||||||
|
public:
|
||||||
|
explicit CurveView(QWidget* parent = Q_NULLPTR);
|
||||||
|
void loadData(ProjectModel::CurveNode* node);
|
||||||
|
void unloadData();
|
||||||
|
ProjectModel::INode* currentNode() const;
|
||||||
|
|
||||||
|
void paintEvent(QPaintEvent* ev);
|
||||||
|
void mousePressEvent(QMouseEvent* ev);
|
||||||
|
void mouseMoveEvent(QMouseEvent* ev);
|
||||||
|
};
|
||||||
|
|
||||||
|
class CurveControls : public QFrame
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
friend class CurveView;
|
||||||
|
QLineEdit* m_lineEdit;
|
||||||
|
QLabel* m_errLabel;
|
||||||
|
QPushButton* m_setExpr;
|
||||||
|
QJSEngine m_engine;
|
||||||
|
CurveEditor* getEditor() const;
|
||||||
|
public:
|
||||||
|
explicit CurveControls(QWidget* parent = Q_NULLPTR);
|
||||||
|
void loadData();
|
||||||
|
void unloadData();
|
||||||
|
void resizeEvent(QResizeEvent* ev);
|
||||||
|
public slots:
|
||||||
|
void exprCommit();
|
||||||
|
};
|
||||||
|
|
||||||
|
class CurveEditor : public EditorWidget
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
friend class CurveView;
|
||||||
|
friend class CurveControls;
|
||||||
|
CurveView* m_curveView;
|
||||||
|
CurveControls* m_controls;
|
||||||
|
public:
|
||||||
|
explicit CurveEditor(QWidget* parent = Q_NULLPTR);
|
||||||
|
bool loadData(ProjectModel::CurveNode* node);
|
||||||
|
void unloadData();
|
||||||
|
ProjectModel::INode* currentNode() const;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif //AMUSE_CURVE_EDITOR_HPP
|
||||||
324
Editor/EditorWidget.cpp
Normal file
@@ -0,0 +1,324 @@
|
|||||||
|
#include "EditorWidget.hpp"
|
||||||
|
#include "MainWindow.hpp"
|
||||||
|
#include <QStandardItemModel>
|
||||||
|
#include <QHBoxLayout>
|
||||||
|
|
||||||
|
EditorWidget::EditorWidget(QWidget* parent)
|
||||||
|
: QWidget(parent)
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void EditorUndoCommand::undo()
|
||||||
|
{
|
||||||
|
g_MainWindow->openEditor(m_node.get());
|
||||||
|
}
|
||||||
|
|
||||||
|
void EditorUndoCommand::redo()
|
||||||
|
{
|
||||||
|
g_MainWindow->openEditor(m_node.get());
|
||||||
|
}
|
||||||
|
|
||||||
|
FieldSlider::FieldSlider(QWidget* parent)
|
||||||
|
: QWidget(parent), m_slider(Qt::Horizontal)
|
||||||
|
{
|
||||||
|
setFixedHeight(22);
|
||||||
|
setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Fixed);
|
||||||
|
QHBoxLayout* layout = new QHBoxLayout;
|
||||||
|
layout->addWidget(&m_slider);
|
||||||
|
layout->addWidget(&m_value);
|
||||||
|
layout->setContentsMargins(QMargins());
|
||||||
|
setLayout(layout);
|
||||||
|
m_value.setFixedWidth(42);
|
||||||
|
connect(&m_slider, SIGNAL(valueChanged(int)), this, SLOT(doValueChanged(int)));
|
||||||
|
m_slider.setValue(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
void FieldSlider::doValueChanged(int value)
|
||||||
|
{
|
||||||
|
m_value.setText(QString::number(value));
|
||||||
|
emit valueChanged(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
FieldDoubleSlider::FieldDoubleSlider(QWidget* parent)
|
||||||
|
: QWidget(parent), m_slider(Qt::Horizontal)
|
||||||
|
{
|
||||||
|
setFixedHeight(22);
|
||||||
|
setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Fixed);
|
||||||
|
QHBoxLayout* layout = new QHBoxLayout;
|
||||||
|
layout->addWidget(&m_slider);
|
||||||
|
layout->addWidget(&m_value);
|
||||||
|
layout->setContentsMargins(QMargins());
|
||||||
|
setLayout(layout);
|
||||||
|
m_value.setFixedWidth(42);
|
||||||
|
connect(&m_slider, SIGNAL(valueChanged(int)), this, SLOT(doValueChanged(int)));
|
||||||
|
m_slider.setRange(0, 1000);
|
||||||
|
m_slider.setValue(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
double FieldDoubleSlider::value() const
|
||||||
|
{
|
||||||
|
double t = m_slider.value() / 1000.0;
|
||||||
|
return t * (m_max - m_min) + m_min;
|
||||||
|
}
|
||||||
|
void FieldDoubleSlider::setValue(double value)
|
||||||
|
{
|
||||||
|
if (value < m_min)
|
||||||
|
value = m_min;
|
||||||
|
else if (value > m_max)
|
||||||
|
value = m_max;
|
||||||
|
|
||||||
|
double t = (value - m_min) / (m_max - m_min);
|
||||||
|
m_slider.setValue(int(t * 1000.0));
|
||||||
|
doValueChanged(int(t * 1000.0));
|
||||||
|
}
|
||||||
|
void FieldDoubleSlider::setRange(double min, double max)
|
||||||
|
{
|
||||||
|
m_min = min; m_max = max;
|
||||||
|
double curValue = value();
|
||||||
|
if (curValue < min)
|
||||||
|
setValue(min);
|
||||||
|
else if (curValue > max)
|
||||||
|
setValue(max);
|
||||||
|
}
|
||||||
|
|
||||||
|
void FieldDoubleSlider::doValueChanged(int value)
|
||||||
|
{
|
||||||
|
double t = value / 1000.0;
|
||||||
|
t = t * (m_max - m_min) + m_min;
|
||||||
|
m_value.setText(QString::number(t, 'g', 2));
|
||||||
|
emit valueChanged(t);
|
||||||
|
}
|
||||||
|
|
||||||
|
FieldProjectNode::FieldProjectNode(ProjectModel::CollectionNode* collection, QWidget* parent)
|
||||||
|
: QWidget(parent), m_comboBox(this), m_button(this)
|
||||||
|
{
|
||||||
|
m_button.setDisabled(true);
|
||||||
|
m_button.setFixedSize(30, 30);
|
||||||
|
m_comboBox.setFixedHeight(30);
|
||||||
|
connect(&m_comboBox, SIGNAL(currentIndexChanged(int)), this, SLOT(_currentIndexChanged(int)));
|
||||||
|
connect(&m_button, SIGNAL(clicked(bool)), this, SLOT(openCurrent()));
|
||||||
|
QIcon icon(QStringLiteral(":/icons/IconForward.svg"));
|
||||||
|
icon.addFile(QStringLiteral(":/icons/IconForwardDisabled.svg"), {}, QIcon::Disabled);
|
||||||
|
m_button.setIcon(icon);
|
||||||
|
QHBoxLayout* layout = new QHBoxLayout;
|
||||||
|
layout->setContentsMargins({});
|
||||||
|
layout->setSpacing(0);
|
||||||
|
layout->addWidget(&m_comboBox);
|
||||||
|
layout->addWidget(&m_button);
|
||||||
|
setLayout(layout);
|
||||||
|
setCollection(collection);
|
||||||
|
}
|
||||||
|
|
||||||
|
void FieldProjectNode::setCollection(ProjectModel::CollectionNode* collection)
|
||||||
|
{
|
||||||
|
m_collection = collection;
|
||||||
|
|
||||||
|
if (!collection)
|
||||||
|
{
|
||||||
|
m_comboBox.setModel(new QStandardItemModel(0, 1, this));
|
||||||
|
m_button.setDisabled(true);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
ProjectModel* model = g_MainWindow->projectModel();
|
||||||
|
m_comboBox.setModel(model->getNullProxy());
|
||||||
|
m_comboBox.setRootModelIndex(model->getNullProxy()->mapFromSource(model->index(collection)));
|
||||||
|
}
|
||||||
|
|
||||||
|
void FieldProjectNode::_currentIndexChanged(int index)
|
||||||
|
{
|
||||||
|
m_button.setEnabled(index != 0);
|
||||||
|
emit currentIndexChanged(index);
|
||||||
|
}
|
||||||
|
|
||||||
|
ProjectModel::BasePoolObjectNode* FieldProjectNode::currentNode() const
|
||||||
|
{
|
||||||
|
int index = m_comboBox.currentIndex();
|
||||||
|
if (index == 0)
|
||||||
|
return nullptr;
|
||||||
|
else
|
||||||
|
return m_collection->nodeOfIndex(index - 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool FieldProjectNode::event(QEvent* ev)
|
||||||
|
{
|
||||||
|
if (ev->type() == QEvent::User)
|
||||||
|
{
|
||||||
|
showPopup();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return QWidget::event(ev);
|
||||||
|
}
|
||||||
|
|
||||||
|
void FieldProjectNode::openCurrent()
|
||||||
|
{
|
||||||
|
if (ProjectModel::BasePoolObjectNode* node = currentNode())
|
||||||
|
if (!g_MainWindow->isUiDisabled())
|
||||||
|
g_MainWindow->openEditor(node);
|
||||||
|
}
|
||||||
|
|
||||||
|
FieldPageObjectNode::FieldPageObjectNode(ProjectModel::GroupNode* group, QWidget* parent)
|
||||||
|
: QWidget(parent), m_comboBox(this), m_button(this)
|
||||||
|
{
|
||||||
|
m_button.setDisabled(true);
|
||||||
|
m_button.setFixedSize(30, 30);
|
||||||
|
m_comboBox.setFixedHeight(30);
|
||||||
|
connect(&m_comboBox, SIGNAL(currentIndexChanged(int)), this, SLOT(_currentIndexChanged(int)));
|
||||||
|
connect(&m_button, SIGNAL(clicked(bool)), this, SLOT(openCurrent()));
|
||||||
|
QIcon icon(QStringLiteral(":/icons/IconForward.svg"));
|
||||||
|
icon.addFile(QStringLiteral(":/icons/IconForwardDisabled.svg"), {}, QIcon::Disabled);
|
||||||
|
m_button.setIcon(icon);
|
||||||
|
QHBoxLayout* layout = new QHBoxLayout;
|
||||||
|
layout->setContentsMargins({});
|
||||||
|
layout->setSpacing(0);
|
||||||
|
layout->addWidget(&m_comboBox);
|
||||||
|
layout->addWidget(&m_button);
|
||||||
|
setLayout(layout);
|
||||||
|
setGroup(group);
|
||||||
|
}
|
||||||
|
|
||||||
|
void FieldPageObjectNode::setGroup(ProjectModel::GroupNode* group)
|
||||||
|
{
|
||||||
|
m_group = group;
|
||||||
|
|
||||||
|
if (!group)
|
||||||
|
{
|
||||||
|
m_comboBox.setModel(new QStandardItemModel(0, 1, this));
|
||||||
|
m_button.setDisabled(true);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
ProjectModel* model = g_MainWindow->projectModel();
|
||||||
|
m_comboBox.setModel(model->getPageObjectProxy());
|
||||||
|
m_comboBox.setRootModelIndex(model->getPageObjectProxy()->mapFromSource(model->index(group)));
|
||||||
|
}
|
||||||
|
|
||||||
|
void FieldPageObjectNode::_currentIndexChanged(int index)
|
||||||
|
{
|
||||||
|
m_button.setEnabled(index != 0);
|
||||||
|
emit currentIndexChanged(index);
|
||||||
|
}
|
||||||
|
|
||||||
|
ProjectModel::BasePoolObjectNode* FieldPageObjectNode::currentNode() const
|
||||||
|
{
|
||||||
|
int index = m_comboBox.currentIndex();
|
||||||
|
if (index == 0)
|
||||||
|
{
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
ProjectModel* model = g_MainWindow->projectModel();
|
||||||
|
return static_cast<ProjectModel::BasePoolObjectNode*>(
|
||||||
|
model->node(model->getPageObjectProxy()->mapToSource(
|
||||||
|
model->getPageObjectProxy()->index(index, 0, m_comboBox.rootModelIndex()))));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool FieldPageObjectNode::event(QEvent* ev)
|
||||||
|
{
|
||||||
|
if (ev->type() == QEvent::User)
|
||||||
|
{
|
||||||
|
showPopup();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return QWidget::event(ev);
|
||||||
|
}
|
||||||
|
|
||||||
|
void FieldPageObjectNode::openCurrent()
|
||||||
|
{
|
||||||
|
if (ProjectModel::BasePoolObjectNode* node = currentNode())
|
||||||
|
if (!g_MainWindow->isUiDisabled())
|
||||||
|
g_MainWindow->openEditor(node);
|
||||||
|
}
|
||||||
|
|
||||||
|
AddRemoveButtons::AddRemoveButtons(QWidget* parent)
|
||||||
|
: QWidget(parent), m_addAction(tr("Add Row")), m_addButton(this),
|
||||||
|
m_removeAction(tr("Remove Row")), m_removeButton(this)
|
||||||
|
{
|
||||||
|
setFixedSize(64, 32);
|
||||||
|
|
||||||
|
m_addAction.setIcon(QIcon(QStringLiteral(":/icons/IconAdd.svg")));
|
||||||
|
m_addButton.setDefaultAction(&m_addAction);
|
||||||
|
m_addButton.setFixedSize(32, 32);
|
||||||
|
m_addButton.move(0, 0);
|
||||||
|
|
||||||
|
m_removeAction.setIcon(QIcon(QStringLiteral(":/icons/IconRemove.svg")));
|
||||||
|
m_removeButton.setDefaultAction(&m_removeAction);
|
||||||
|
m_removeButton.setFixedSize(32, 32);
|
||||||
|
m_removeButton.move(32, 0);
|
||||||
|
m_removeAction.setEnabled(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
static QIcon ListingDeleteIcon;
|
||||||
|
static QIcon ListingDeleteHoveredIcon;
|
||||||
|
|
||||||
|
void ListingDeleteButton::enterEvent(QEvent* event)
|
||||||
|
{
|
||||||
|
setIcon(ListingDeleteHoveredIcon);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ListingDeleteButton::leaveEvent(QEvent* event)
|
||||||
|
{
|
||||||
|
setIcon(ListingDeleteIcon);
|
||||||
|
}
|
||||||
|
|
||||||
|
ListingDeleteButton::ListingDeleteButton(QWidget* parent)
|
||||||
|
: QPushButton(parent)
|
||||||
|
{
|
||||||
|
if (ListingDeleteIcon.isNull())
|
||||||
|
ListingDeleteIcon = QIcon(QStringLiteral(":/icons/IconSoundMacroDelete.svg"));
|
||||||
|
if (ListingDeleteHoveredIcon.isNull())
|
||||||
|
ListingDeleteHoveredIcon = QIcon(QStringLiteral(":/icons/IconSoundMacroDeleteHovered.svg"));
|
||||||
|
|
||||||
|
setVisible(false);
|
||||||
|
setFixedSize(21, 21);
|
||||||
|
setFlat(true);
|
||||||
|
setToolTip(tr("Delete this SoundMacro"));
|
||||||
|
setIcon(ListingDeleteIcon);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool BaseObjectDelegate::editorEvent(QEvent *event, QAbstractItemModel* model,
|
||||||
|
const QStyleOptionViewItem &option, const QModelIndex &index)
|
||||||
|
{
|
||||||
|
if (event->type() == QEvent::MouseButtonPress)
|
||||||
|
{
|
||||||
|
QMouseEvent* ev = static_cast<QMouseEvent*>(event);
|
||||||
|
if (ev->button() == Qt::RightButton)
|
||||||
|
{
|
||||||
|
ProjectModel::INode* node = getNode(model, index);
|
||||||
|
|
||||||
|
ContextMenu* menu = new ContextMenu;
|
||||||
|
|
||||||
|
QAction* openEditorAction = new QAction(tr("Open in Editor"), menu);
|
||||||
|
openEditorAction->setData(QVariant::fromValue((void*)node));
|
||||||
|
openEditorAction->setIcon(QIcon::fromTheme(QStringLiteral("document-edit")));
|
||||||
|
connect(openEditorAction, SIGNAL(triggered()), this, SLOT(doOpenEditor()));
|
||||||
|
menu->addAction(openEditorAction);
|
||||||
|
|
||||||
|
QAction* findUsagesAction = new QAction(tr("Find Usages"), menu);
|
||||||
|
findUsagesAction->setData(QVariant::fromValue((void*)node));
|
||||||
|
findUsagesAction->setIcon(QIcon::fromTheme(QStringLiteral("edit-find")));
|
||||||
|
connect(findUsagesAction, SIGNAL(triggered()), this, SLOT(doFindUsages()));
|
||||||
|
menu->addAction(findUsagesAction);
|
||||||
|
|
||||||
|
menu->popup(ev->globalPos());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
void BaseObjectDelegate::doOpenEditor()
|
||||||
|
{
|
||||||
|
QAction* act = static_cast<QAction*>(sender());
|
||||||
|
if (ProjectModel::INode* node = reinterpret_cast<ProjectModel::INode*>(act->data().value<void*>()))
|
||||||
|
g_MainWindow->openEditor(node);
|
||||||
|
}
|
||||||
|
|
||||||
|
void BaseObjectDelegate::doFindUsages()
|
||||||
|
{
|
||||||
|
QAction* act = static_cast<QAction*>(sender());
|
||||||
|
if (ProjectModel::INode* node = reinterpret_cast<ProjectModel::INode*>(act->data().value<void*>()))
|
||||||
|
g_MainWindow->findUsages(node);
|
||||||
|
}
|
||||||
254
Editor/EditorWidget.hpp
Normal file
@@ -0,0 +1,254 @@
|
|||||||
|
#ifndef AMUSE_EDITOR_WIDGET_HPP
|
||||||
|
#define AMUSE_EDITOR_WIDGET_HPP
|
||||||
|
|
||||||
|
#include <QWidget>
|
||||||
|
#include <QUndoCommand>
|
||||||
|
#include <QApplication>
|
||||||
|
#include <QSpinBox>
|
||||||
|
#include <QComboBox>
|
||||||
|
#include <QWheelEvent>
|
||||||
|
#include <QItemEditorFactory>
|
||||||
|
#include <QToolButton>
|
||||||
|
#include <QAction>
|
||||||
|
#include <QPushButton>
|
||||||
|
#include <QLabel>
|
||||||
|
#include <QMenu>
|
||||||
|
#include <QStyledItemDelegate>
|
||||||
|
#include "ProjectModel.hpp"
|
||||||
|
|
||||||
|
class EditorWidget : public QWidget
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
public:
|
||||||
|
explicit EditorWidget(QWidget* parent = Q_NULLPTR);
|
||||||
|
virtual bool valid() const { return true; }
|
||||||
|
virtual void unloadData() {}
|
||||||
|
virtual ProjectModel::INode* currentNode() const { return nullptr; }
|
||||||
|
virtual void setEditorEnabled(bool en) { setEnabled(en); }
|
||||||
|
virtual AmuseItemEditFlags itemEditFlags() const { return AmuseItemNone; }
|
||||||
|
public slots:
|
||||||
|
virtual void itemCutAction() {}
|
||||||
|
virtual void itemCopyAction() {}
|
||||||
|
virtual void itemPasteAction() {}
|
||||||
|
virtual void itemDeleteAction() {}
|
||||||
|
};
|
||||||
|
|
||||||
|
class EditorUndoCommand : public QUndoCommand
|
||||||
|
{
|
||||||
|
protected:
|
||||||
|
amuse::ObjToken<ProjectModel::INode> m_node;
|
||||||
|
enum class Id
|
||||||
|
{
|
||||||
|
SMChangeVal,
|
||||||
|
SampLoop,
|
||||||
|
SampPitch,
|
||||||
|
ADSRAttack,
|
||||||
|
ADSRDecay,
|
||||||
|
ADSRSustain,
|
||||||
|
ADSRAttackAndDecay,
|
||||||
|
ADSRDecayAndSustain,
|
||||||
|
ADSRRelease,
|
||||||
|
ADSRDLS,
|
||||||
|
ADSRVelToAttack,
|
||||||
|
ADSRKeyToDecay,
|
||||||
|
CurveEdit
|
||||||
|
};
|
||||||
|
public:
|
||||||
|
EditorUndoCommand(amuse::ObjToken<ProjectModel::INode> node,
|
||||||
|
const QString& text, QUndoCommand* parent = nullptr)
|
||||||
|
: QUndoCommand(text, parent), m_node(node) {}
|
||||||
|
void undo();
|
||||||
|
void redo();
|
||||||
|
};
|
||||||
|
|
||||||
|
class FieldSpinBox : public QSpinBox
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
public:
|
||||||
|
explicit FieldSpinBox(QWidget* parent = Q_NULLPTR)
|
||||||
|
: QSpinBox(parent) {}
|
||||||
|
|
||||||
|
/* Don't scroll */
|
||||||
|
void wheelEvent(QWheelEvent* event) { event->ignore(); }
|
||||||
|
};
|
||||||
|
|
||||||
|
class FieldSlider : public QWidget
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
QSlider m_slider;
|
||||||
|
QLabel m_value;
|
||||||
|
public:
|
||||||
|
explicit FieldSlider(QWidget* parent = Q_NULLPTR);
|
||||||
|
|
||||||
|
/* Don't scroll */
|
||||||
|
void wheelEvent(QWheelEvent* event) { event->ignore(); }
|
||||||
|
|
||||||
|
int value() const { return m_slider.value(); }
|
||||||
|
void setValue(int value) { m_slider.setValue(value); doValueChanged(value); }
|
||||||
|
void setRange(int min, int max) { m_slider.setRange(min, max); }
|
||||||
|
|
||||||
|
private slots:
|
||||||
|
void doValueChanged(int value);
|
||||||
|
signals:
|
||||||
|
void valueChanged(int value);
|
||||||
|
};
|
||||||
|
|
||||||
|
class FieldDoubleSlider : public QWidget
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
QSlider m_slider;
|
||||||
|
QLabel m_value;
|
||||||
|
double m_min = 0.0;
|
||||||
|
double m_max = 1.0;
|
||||||
|
public:
|
||||||
|
explicit FieldDoubleSlider(QWidget* parent = Q_NULLPTR);
|
||||||
|
|
||||||
|
/* Don't scroll */
|
||||||
|
void wheelEvent(QWheelEvent* event) { event->ignore(); }
|
||||||
|
|
||||||
|
double value() const;
|
||||||
|
void setValue(double value);
|
||||||
|
void setRange(double min, double max);
|
||||||
|
|
||||||
|
private slots:
|
||||||
|
void doValueChanged(int value);
|
||||||
|
signals:
|
||||||
|
void valueChanged(double value);
|
||||||
|
};
|
||||||
|
|
||||||
|
class FieldComboBox : public QComboBox
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
public:
|
||||||
|
explicit FieldComboBox(QWidget* parent = Q_NULLPTR)
|
||||||
|
: QComboBox(parent) {}
|
||||||
|
|
||||||
|
/* Don't scroll */
|
||||||
|
void wheelEvent(QWheelEvent* event) { event->ignore(); }
|
||||||
|
};
|
||||||
|
|
||||||
|
class FieldProjectNode : public QWidget
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
ProjectModel::CollectionNode* m_collection;
|
||||||
|
FieldComboBox m_comboBox;
|
||||||
|
QPushButton m_button;
|
||||||
|
public:
|
||||||
|
explicit FieldProjectNode(ProjectModel::CollectionNode* collection = Q_NULLPTR, QWidget* parent = Q_NULLPTR);
|
||||||
|
void setCollection(ProjectModel::CollectionNode* collection);
|
||||||
|
ProjectModel::CollectionNode* collection() const { return m_collection; }
|
||||||
|
int currentIndex() const { return m_comboBox.currentIndex(); }
|
||||||
|
void setCurrentIndex(int index) { m_comboBox.setCurrentIndex(index); }
|
||||||
|
void showPopup() { m_comboBox.showPopup(); }
|
||||||
|
ProjectModel::BasePoolObjectNode* currentNode() const;
|
||||||
|
bool event(QEvent* ev);
|
||||||
|
private slots:
|
||||||
|
void _currentIndexChanged(int);
|
||||||
|
public slots:
|
||||||
|
void openCurrent();
|
||||||
|
signals:
|
||||||
|
void currentIndexChanged(int);
|
||||||
|
};
|
||||||
|
|
||||||
|
class FieldPageObjectNode : public QWidget
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
ProjectModel::GroupNode* m_group;
|
||||||
|
FieldComboBox m_comboBox;
|
||||||
|
QPushButton m_button;
|
||||||
|
public:
|
||||||
|
explicit FieldPageObjectNode(ProjectModel::GroupNode* group = Q_NULLPTR, QWidget* parent = Q_NULLPTR);
|
||||||
|
void setGroup(ProjectModel::GroupNode* group);
|
||||||
|
ProjectModel::GroupNode* group() const { return m_group; }
|
||||||
|
int currentIndex() const { return m_comboBox.currentIndex(); }
|
||||||
|
void setCurrentIndex(int index) { m_comboBox.setCurrentIndex(index); }
|
||||||
|
QModelIndex rootModelIndex() const { return m_comboBox.rootModelIndex(); }
|
||||||
|
void showPopup() { m_comboBox.showPopup(); }
|
||||||
|
ProjectModel::BasePoolObjectNode* currentNode() const;
|
||||||
|
bool event(QEvent* ev);
|
||||||
|
private slots:
|
||||||
|
void _currentIndexChanged(int);
|
||||||
|
public slots:
|
||||||
|
void openCurrent();
|
||||||
|
signals:
|
||||||
|
void currentIndexChanged(int);
|
||||||
|
};
|
||||||
|
|
||||||
|
template <class T>
|
||||||
|
class EditorFieldNode : public T
|
||||||
|
{
|
||||||
|
bool m_deferPopupOpen = true;
|
||||||
|
public:
|
||||||
|
using T::T;
|
||||||
|
bool shouldPopupOpen()
|
||||||
|
{
|
||||||
|
bool ret = m_deferPopupOpen;
|
||||||
|
m_deferPopupOpen = false;
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
using EditorFieldProjectNode = EditorFieldNode<FieldProjectNode>;
|
||||||
|
using EditorFieldPageObjectNode = EditorFieldNode<FieldPageObjectNode>;
|
||||||
|
|
||||||
|
template <int MIN, int MAX>
|
||||||
|
class RangedValueFactory : public QItemEditorFactory
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
QWidget* createEditor(int userType, QWidget *parent) const
|
||||||
|
{
|
||||||
|
QSpinBox* sb = new QSpinBox(parent);
|
||||||
|
sb->setFrame(false);
|
||||||
|
sb->setMinimum(MIN);
|
||||||
|
sb->setMaximum(MAX);
|
||||||
|
return sb;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
class AddRemoveButtons : public QWidget
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
QAction m_addAction;
|
||||||
|
QToolButton m_addButton;
|
||||||
|
QAction m_removeAction;
|
||||||
|
QToolButton m_removeButton;
|
||||||
|
public:
|
||||||
|
explicit AddRemoveButtons(QWidget* parent = Q_NULLPTR);
|
||||||
|
QAction* addAction() { return &m_addAction; }
|
||||||
|
QAction* removeAction() { return &m_removeAction; }
|
||||||
|
};
|
||||||
|
|
||||||
|
class ListingDeleteButton : public QPushButton
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
public:
|
||||||
|
explicit ListingDeleteButton(QWidget* parent = Q_NULLPTR);
|
||||||
|
void enterEvent(QEvent* event);
|
||||||
|
void leaveEvent(QEvent* event);
|
||||||
|
};
|
||||||
|
|
||||||
|
class ContextMenu : public QMenu
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
void hideEvent(QHideEvent* ev)
|
||||||
|
{
|
||||||
|
QMenu::hideEvent(ev);
|
||||||
|
deleteLater();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
class BaseObjectDelegate : public QStyledItemDelegate
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
protected:
|
||||||
|
virtual ProjectModel::INode* getNode(const QAbstractItemModel* model, const QModelIndex& index) const = 0;
|
||||||
|
public:
|
||||||
|
explicit BaseObjectDelegate(QObject* parent = Q_NULLPTR) : QStyledItemDelegate(parent) {}
|
||||||
|
bool editorEvent(QEvent *event, QAbstractItemModel *model,
|
||||||
|
const QStyleOptionViewItem &option, const QModelIndex &index);
|
||||||
|
private slots:
|
||||||
|
void doOpenEditor();
|
||||||
|
void doFindUsages();
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif //AMUSE_EDITOR_WIDGET_HPP
|
||||||
271
Editor/KeyboardWidget.cpp
Normal file
@@ -0,0 +1,271 @@
|
|||||||
|
#include "KeyboardWidget.hpp"
|
||||||
|
#include <QHBoxLayout>
|
||||||
|
#include <QSvgRenderer>
|
||||||
|
#include <QMouseEvent>
|
||||||
|
#include <QScrollArea>
|
||||||
|
#include <QApplication>
|
||||||
|
#include <QScrollBar>
|
||||||
|
|
||||||
|
const QString NaturalKeyNames[] =
|
||||||
|
{
|
||||||
|
QStringLiteral("C"),
|
||||||
|
QStringLiteral("D"),
|
||||||
|
QStringLiteral("E"),
|
||||||
|
QStringLiteral("F"),
|
||||||
|
QStringLiteral("G"),
|
||||||
|
QStringLiteral("A"),
|
||||||
|
QStringLiteral("B")
|
||||||
|
};
|
||||||
|
|
||||||
|
const QString SharpKeyNames[] =
|
||||||
|
{
|
||||||
|
QStringLiteral("Cs"),
|
||||||
|
QStringLiteral("Ds"),
|
||||||
|
QStringLiteral("Fs"),
|
||||||
|
QStringLiteral("Gs"),
|
||||||
|
QStringLiteral("As")
|
||||||
|
};
|
||||||
|
|
||||||
|
const QString KeyStrings[] =
|
||||||
|
{
|
||||||
|
QStringLiteral("C"),
|
||||||
|
QStringLiteral("C#"),
|
||||||
|
QStringLiteral("D"),
|
||||||
|
QStringLiteral("D#"),
|
||||||
|
QStringLiteral("E"),
|
||||||
|
QStringLiteral("F"),
|
||||||
|
QStringLiteral("F#"),
|
||||||
|
QStringLiteral("G"),
|
||||||
|
QStringLiteral("G#"),
|
||||||
|
QStringLiteral("A"),
|
||||||
|
QStringLiteral("A#"),
|
||||||
|
QStringLiteral("B")
|
||||||
|
};
|
||||||
|
|
||||||
|
const int NaturalKeyNumbers[] =
|
||||||
|
{
|
||||||
|
0, 2, 4, 5, 7, 9, 11
|
||||||
|
};
|
||||||
|
|
||||||
|
const int SharpKeyNumbers[] =
|
||||||
|
{
|
||||||
|
1, 3, 6, 8, 10
|
||||||
|
};
|
||||||
|
|
||||||
|
KeyboardOctave::KeyboardOctave(int octave, const QString& svgPath, QWidget* parent)
|
||||||
|
: QSvgWidget(svgPath, parent), m_octave(octave)
|
||||||
|
{
|
||||||
|
for (int i = 0; i < 7; ++i)
|
||||||
|
if (renderer()->elementExists(NaturalKeyNames[i]))
|
||||||
|
m_natural[i] = renderer()->matrixForElement(NaturalKeyNames[i]).
|
||||||
|
mapRect(renderer()->boundsOnElement(NaturalKeyNames[i]));
|
||||||
|
|
||||||
|
for (int i = 0; i < 5; ++i)
|
||||||
|
if (renderer()->elementExists(SharpKeyNames[i]))
|
||||||
|
m_sharp[i] = renderer()->matrixForElement(SharpKeyNames[i]).
|
||||||
|
mapRect(renderer()->boundsOnElement(SharpKeyNames[i]));
|
||||||
|
|
||||||
|
/* The parent keyboard manages all mouse events */
|
||||||
|
setAttribute(Qt::WA_TransparentForMouseEvents);
|
||||||
|
}
|
||||||
|
|
||||||
|
int KeyboardOctave::getKey(const QPoint& localPos) const
|
||||||
|
{
|
||||||
|
QPointF localPoint = m_widgetToSvg.map(localPos);
|
||||||
|
for (int i = 0; i < 5; ++i)
|
||||||
|
if (m_sharp[i].contains(localPoint))
|
||||||
|
return SharpKeyNumbers[i];
|
||||||
|
for (int i = 0; i < 7; ++i)
|
||||||
|
if (m_natural[i].contains(localPoint))
|
||||||
|
return NaturalKeyNumbers[i];
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
void KeyboardOctave::resizeEvent(QResizeEvent *event)
|
||||||
|
{
|
||||||
|
m_widgetToSvg = RectToRect(rect(), renderer()->viewBoxF());
|
||||||
|
}
|
||||||
|
|
||||||
|
KeyboardWidget::KeyboardWidget(QWidget* parent)
|
||||||
|
: QWidget(parent)
|
||||||
|
{
|
||||||
|
QHBoxLayout* layout = new QHBoxLayout(this);
|
||||||
|
layout->setContentsMargins(QMargins());
|
||||||
|
layout->setSpacing(0);
|
||||||
|
|
||||||
|
for (int i = 0; i < 10; ++i)
|
||||||
|
{
|
||||||
|
m_widgets[i] = new KeyboardOctave(i, QStringLiteral(":/bg/keyboard.svg"), this);
|
||||||
|
m_widgets[i]->setGeometry(QRect(0, 0, 141, 50));
|
||||||
|
m_widgets[i]->setSizePolicy(QSizePolicy(QSizePolicy::Fixed, QSizePolicy::Preferred));
|
||||||
|
layout->addWidget(m_widgets[i]);
|
||||||
|
}
|
||||||
|
|
||||||
|
m_widgets[10] = new KeyboardOctave(10, QStringLiteral(":/bg/keyboard_last.svg"), this);
|
||||||
|
m_widgets[10]->setGeometry(QRect(0, 0, 101, 50));
|
||||||
|
m_widgets[10]->setSizePolicy(QSizePolicy(QSizePolicy::Fixed, QSizePolicy::Preferred));
|
||||||
|
layout->addWidget(m_widgets[10]);
|
||||||
|
|
||||||
|
setLayout(layout);
|
||||||
|
setMouseTracking(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
std::pair<int, int> KeyboardWidget::_getOctaveAndKey(QMouseEvent* event) const
|
||||||
|
{
|
||||||
|
for (KeyboardOctave* oct : m_widgets)
|
||||||
|
{
|
||||||
|
QPoint localPos = oct->mapFromParent(event->pos());
|
||||||
|
if (oct->rect().contains(localPos))
|
||||||
|
return {oct->getOctave(), oct->getKey(localPos)};
|
||||||
|
}
|
||||||
|
return {-1, -1};
|
||||||
|
}
|
||||||
|
|
||||||
|
void KeyboardWidget::_startKey(int octave, int key)
|
||||||
|
{
|
||||||
|
emit notePressed(octave * 12 + key);
|
||||||
|
}
|
||||||
|
|
||||||
|
void KeyboardWidget::_stopKey()
|
||||||
|
{
|
||||||
|
emit noteReleased();
|
||||||
|
}
|
||||||
|
|
||||||
|
void KeyboardWidget::_moveOnKey(int octave, int key)
|
||||||
|
{
|
||||||
|
if (m_lastOctave != octave || m_lastKey != key)
|
||||||
|
{
|
||||||
|
m_lastOctave = octave;
|
||||||
|
m_lastKey = key;
|
||||||
|
if (m_statusFocus)
|
||||||
|
m_statusFocus->setMessage(QStringLiteral("%1%2 (%3)").
|
||||||
|
arg(KeyStrings[key]).arg(octave - 1).arg(octave * 12 + key));
|
||||||
|
if (m_holding)
|
||||||
|
_startKey(octave, key);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void KeyboardWidget::_pressOnKey(int octave, int key)
|
||||||
|
{
|
||||||
|
_moveOnKey(octave, key);
|
||||||
|
m_holding = true;
|
||||||
|
_startKey(octave, key);
|
||||||
|
}
|
||||||
|
|
||||||
|
void KeyboardWidget::mouseMoveEvent(QMouseEvent* event)
|
||||||
|
{
|
||||||
|
std::pair<int, int> ok = _getOctaveAndKey(event);
|
||||||
|
if (ok.first != -1 && ok.second != -1)
|
||||||
|
_moveOnKey(ok.first, ok.second);
|
||||||
|
}
|
||||||
|
|
||||||
|
void KeyboardWidget::mousePressEvent(QMouseEvent* event)
|
||||||
|
{
|
||||||
|
std::pair<int, int> ok = _getOctaveAndKey(event);
|
||||||
|
if (ok.first != -1 && ok.second != -1)
|
||||||
|
_pressOnKey(ok.first, ok.second);
|
||||||
|
}
|
||||||
|
|
||||||
|
void KeyboardWidget::mouseReleaseEvent(QMouseEvent* event)
|
||||||
|
{
|
||||||
|
_stopKey();
|
||||||
|
m_holding = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
void KeyboardWidget::enterEvent(QEvent* event)
|
||||||
|
{
|
||||||
|
if (m_statusFocus)
|
||||||
|
m_statusFocus->enter();
|
||||||
|
}
|
||||||
|
|
||||||
|
void KeyboardWidget::leaveEvent(QEvent* event)
|
||||||
|
{
|
||||||
|
if (m_statusFocus)
|
||||||
|
m_statusFocus->exit();
|
||||||
|
}
|
||||||
|
|
||||||
|
void KeyboardWidget::wheelEvent(QWheelEvent* event)
|
||||||
|
{
|
||||||
|
if (QScrollArea* scroll = qobject_cast<QScrollArea*>(parentWidget()->parentWidget()))
|
||||||
|
{
|
||||||
|
/* Send wheel event directly to the scroll bar */
|
||||||
|
QApplication::sendEvent(scroll->horizontalScrollBar(), event);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void KeyboardWidget::showEvent(QShowEvent* event)
|
||||||
|
{
|
||||||
|
if (QScrollArea* scroll = qobject_cast<QScrollArea*>(parentWidget()->parentWidget()))
|
||||||
|
{
|
||||||
|
/* Scroll to C1 */
|
||||||
|
scroll->ensureVisible(141 * 2 + scroll->width(), 0, 0, 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
KeyboardSlider::KeyboardSlider(QWidget* parent)
|
||||||
|
: QSlider(parent)
|
||||||
|
{}
|
||||||
|
|
||||||
|
void KeyboardSlider::enterEvent(QEvent* event)
|
||||||
|
{
|
||||||
|
if (m_statusFocus)
|
||||||
|
m_statusFocus->enter();
|
||||||
|
}
|
||||||
|
|
||||||
|
void KeyboardSlider::leaveEvent(QEvent* event)
|
||||||
|
{
|
||||||
|
if (m_statusFocus)
|
||||||
|
m_statusFocus->exit();
|
||||||
|
}
|
||||||
|
|
||||||
|
void KeyboardSlider::setStatusFocus(StatusBarFocus* statusFocus)
|
||||||
|
{
|
||||||
|
m_statusFocus = statusFocus;
|
||||||
|
QString str = stringOfValue(value());
|
||||||
|
m_statusFocus->setMessage(str);
|
||||||
|
setToolTip(str);
|
||||||
|
}
|
||||||
|
|
||||||
|
void KeyboardSlider::sliderChange(SliderChange change)
|
||||||
|
{
|
||||||
|
QSlider::sliderChange(change);
|
||||||
|
if (m_statusFocus && change == QAbstractSlider::SliderValueChange)
|
||||||
|
{
|
||||||
|
QString str = stringOfValue(value());
|
||||||
|
m_statusFocus->setMessage(str);
|
||||||
|
setToolTip(str);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
VelocitySlider::VelocitySlider(QWidget* parent)
|
||||||
|
: KeyboardSlider(parent)
|
||||||
|
{}
|
||||||
|
|
||||||
|
QString VelocitySlider::stringOfValue(int value) const
|
||||||
|
{
|
||||||
|
return tr("Velocity: %1").arg(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
ModulationSlider::ModulationSlider(QWidget* parent)
|
||||||
|
: KeyboardSlider(parent)
|
||||||
|
{}
|
||||||
|
|
||||||
|
QString ModulationSlider::stringOfValue(int value) const
|
||||||
|
{
|
||||||
|
return tr("Modulation: %1").arg(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
PitchSlider::PitchSlider(QWidget* parent)
|
||||||
|
: KeyboardSlider(parent)
|
||||||
|
{}
|
||||||
|
|
||||||
|
QString PitchSlider::stringOfValue(int value) const
|
||||||
|
{
|
||||||
|
return tr("Pitch: %1").arg(value / 2048.0, 0, 'g', 2);
|
||||||
|
}
|
||||||
|
|
||||||
|
void PitchSlider::mouseReleaseEvent(QMouseEvent *ev)
|
||||||
|
{
|
||||||
|
KeyboardSlider::mouseReleaseEvent(ev);
|
||||||
|
setValue(0);
|
||||||
|
}
|
||||||
106
Editor/KeyboardWidget.hpp
Normal file
@@ -0,0 +1,106 @@
|
|||||||
|
#ifndef AMUSE_KEYBOARD_WIDGET_HPP
|
||||||
|
#define AMUSE_KEYBOARD_WIDGET_HPP
|
||||||
|
|
||||||
|
#include <QWidget>
|
||||||
|
#include <QSvgWidget>
|
||||||
|
#include <QSlider>
|
||||||
|
#include <QWheelEvent>
|
||||||
|
#include "StatusBarWidget.hpp"
|
||||||
|
#include "Common.hpp"
|
||||||
|
|
||||||
|
extern const QString NaturalKeyNames[7];
|
||||||
|
extern const QString SharpKeyNames[5];
|
||||||
|
extern const QString KeyStrings[12];
|
||||||
|
extern const int NaturalKeyNumbers[7];
|
||||||
|
extern const int SharpKeyNumbers[5];
|
||||||
|
|
||||||
|
class KeyboardWidget;
|
||||||
|
|
||||||
|
class KeyboardOctave : public QSvgWidget
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
int m_octave;
|
||||||
|
QRectF m_natural[7];
|
||||||
|
QRectF m_sharp[5];
|
||||||
|
QTransform m_widgetToSvg;
|
||||||
|
public:
|
||||||
|
explicit KeyboardOctave(int octave, const QString& svgPath, QWidget* parent = Q_NULLPTR);
|
||||||
|
int getOctave() const { return m_octave; }
|
||||||
|
int getKey(const QPoint& localPos) const;
|
||||||
|
void resizeEvent(QResizeEvent *event);
|
||||||
|
};
|
||||||
|
|
||||||
|
class KeyboardWidget : public QWidget
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
KeyboardOctave* m_widgets[11];
|
||||||
|
StatusBarFocus* m_statusFocus = nullptr;
|
||||||
|
int m_lastOctave = -1;
|
||||||
|
int m_lastKey = -1;
|
||||||
|
bool m_holding = false;
|
||||||
|
|
||||||
|
std::pair<int, int> _getOctaveAndKey(QMouseEvent* event) const;
|
||||||
|
void _startKey(int octave, int key);
|
||||||
|
void _stopKey();
|
||||||
|
void _moveOnKey(int octave, int key);
|
||||||
|
void _pressOnKey(int octave, int key);
|
||||||
|
|
||||||
|
public:
|
||||||
|
explicit KeyboardWidget(QWidget* parent = Q_NULLPTR);
|
||||||
|
void setStatusFocus(StatusBarFocus* statusFocus) { m_statusFocus = statusFocus; }
|
||||||
|
|
||||||
|
void mouseMoveEvent(QMouseEvent* event);
|
||||||
|
void mousePressEvent(QMouseEvent* event);
|
||||||
|
void mouseReleaseEvent(QMouseEvent* event);
|
||||||
|
void enterEvent(QEvent* event);
|
||||||
|
void leaveEvent(QEvent* event);
|
||||||
|
void wheelEvent(QWheelEvent *event);
|
||||||
|
void showEvent(QShowEvent *event);
|
||||||
|
|
||||||
|
signals:
|
||||||
|
void notePressed(int key);
|
||||||
|
void noteReleased();
|
||||||
|
};
|
||||||
|
|
||||||
|
class KeyboardSlider : public QSlider
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
protected:
|
||||||
|
StatusBarFocus* m_statusFocus = nullptr;
|
||||||
|
virtual QString stringOfValue(int value) const = 0;
|
||||||
|
public:
|
||||||
|
explicit KeyboardSlider(QWidget* parent = Q_NULLPTR);
|
||||||
|
void enterEvent(QEvent* event);
|
||||||
|
void leaveEvent(QEvent* event);
|
||||||
|
void setStatusFocus(StatusBarFocus* statusFocus);
|
||||||
|
void sliderChange(SliderChange change);
|
||||||
|
};
|
||||||
|
|
||||||
|
class VelocitySlider : public KeyboardSlider
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
QString stringOfValue(int value) const;
|
||||||
|
public:
|
||||||
|
explicit VelocitySlider(QWidget* parent = Q_NULLPTR);
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
class ModulationSlider : public KeyboardSlider
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
QString stringOfValue(int value) const;
|
||||||
|
public:
|
||||||
|
explicit ModulationSlider(QWidget* parent = Q_NULLPTR);
|
||||||
|
};
|
||||||
|
|
||||||
|
class PitchSlider : public KeyboardSlider
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
QString stringOfValue(int value) const;
|
||||||
|
public:
|
||||||
|
explicit PitchSlider(QWidget* parent = Q_NULLPTR);
|
||||||
|
void mouseReleaseEvent(QMouseEvent *ev);
|
||||||
|
void wheelEvent(QWheelEvent* ev) { ev->ignore(); }
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif //AMUSE_KEYBOARD_WIDGET_HPP
|
||||||
600
Editor/KeymapEditor.cpp
Normal file
@@ -0,0 +1,600 @@
|
|||||||
|
#include "KeymapEditor.hpp"
|
||||||
|
#include "MainWindow.hpp"
|
||||||
|
#include "KeyboardWidget.hpp"
|
||||||
|
#include <QVBoxLayout>
|
||||||
|
#include <QPainter>
|
||||||
|
#include <QScrollBar>
|
||||||
|
|
||||||
|
static const int HueTable[] =
|
||||||
|
{
|
||||||
|
0, 30, 60, 80, 120, 170, 200, 240, 280, 320
|
||||||
|
};
|
||||||
|
|
||||||
|
static const int SaturationTable[] =
|
||||||
|
{
|
||||||
|
255, 255, 255, 255, 255, 127, 127, 127, 127, 127, 63, 63, 63
|
||||||
|
};
|
||||||
|
|
||||||
|
static const int ValueTable[] =
|
||||||
|
{
|
||||||
|
240, 200, 160, 120, 80, 240, 200, 160, 120, 80, 240, 200, 160
|
||||||
|
};
|
||||||
|
|
||||||
|
static const QPoint PointTable[] =
|
||||||
|
{
|
||||||
|
{21, 180},
|
||||||
|
{41, 104},
|
||||||
|
{61, 180},
|
||||||
|
{86, 104},
|
||||||
|
{101, 180},
|
||||||
|
{141, 180},
|
||||||
|
{156, 104},
|
||||||
|
{181, 180},
|
||||||
|
{201, 104},
|
||||||
|
{221, 180},
|
||||||
|
{246, 104},
|
||||||
|
{261, 180}
|
||||||
|
};
|
||||||
|
|
||||||
|
static const int RadiusTable[] =
|
||||||
|
{
|
||||||
|
14,
|
||||||
|
10,
|
||||||
|
14,
|
||||||
|
10,
|
||||||
|
14,
|
||||||
|
14,
|
||||||
|
10,
|
||||||
|
14,
|
||||||
|
10,
|
||||||
|
14,
|
||||||
|
10,
|
||||||
|
14
|
||||||
|
};
|
||||||
|
|
||||||
|
static const QColor PenColorTable[] =
|
||||||
|
{
|
||||||
|
Qt::black,
|
||||||
|
Qt::white,
|
||||||
|
Qt::black,
|
||||||
|
Qt::white,
|
||||||
|
Qt::black,
|
||||||
|
Qt::black,
|
||||||
|
Qt::white,
|
||||||
|
Qt::black,
|
||||||
|
Qt::white,
|
||||||
|
Qt::black,
|
||||||
|
Qt::white,
|
||||||
|
Qt::black
|
||||||
|
};
|
||||||
|
|
||||||
|
static const QColor NeutralColorTable[] =
|
||||||
|
{
|
||||||
|
Qt::white,
|
||||||
|
Qt::black,
|
||||||
|
Qt::white,
|
||||||
|
Qt::black,
|
||||||
|
Qt::white,
|
||||||
|
Qt::white,
|
||||||
|
Qt::black,
|
||||||
|
Qt::white,
|
||||||
|
Qt::black,
|
||||||
|
Qt::white,
|
||||||
|
Qt::black,
|
||||||
|
Qt::white
|
||||||
|
};
|
||||||
|
|
||||||
|
PaintButton::PaintButton(QWidget* parent)
|
||||||
|
: QPushButton(parent)
|
||||||
|
{
|
||||||
|
setIcon(QIcon(QStringLiteral(":/icons/IconPaintbrush.svg")));
|
||||||
|
setIconSize(QSize(26, 26));
|
||||||
|
setFixedSize(46, 46);
|
||||||
|
setToolTip(tr("Activate brush to apply values to keys"));
|
||||||
|
}
|
||||||
|
|
||||||
|
KeymapEditor* KeymapView::getEditor() const
|
||||||
|
{
|
||||||
|
return qobject_cast<KeymapEditor*>(parentWidget()->parentWidget()->parentWidget());
|
||||||
|
}
|
||||||
|
|
||||||
|
void KeymapView::loadData(ProjectModel::KeymapNode* node)
|
||||||
|
{
|
||||||
|
m_node = node;
|
||||||
|
}
|
||||||
|
|
||||||
|
void KeymapView::unloadData()
|
||||||
|
{
|
||||||
|
m_node.reset();
|
||||||
|
std::fill(std::begin(m_keyPalettes), std::end(m_keyPalettes), -1);
|
||||||
|
}
|
||||||
|
|
||||||
|
ProjectModel::INode* KeymapView::currentNode() const
|
||||||
|
{
|
||||||
|
return m_node.get();
|
||||||
|
}
|
||||||
|
|
||||||
|
void KeymapView::drawKey(QPainter& painter, const QRect& octaveRect, qreal penWidth,
|
||||||
|
const QColor* keyPalette, int o, int k) const
|
||||||
|
{
|
||||||
|
int keyIdx = o * 12 + k;
|
||||||
|
int keyPalIdx = m_keyPalettes[keyIdx];
|
||||||
|
painter.setPen(QPen(PenColorTable[k], penWidth));
|
||||||
|
painter.setBrush(keyPalIdx < 0 ? NeutralColorTable[k] : keyPalette[keyPalIdx]);
|
||||||
|
painter.drawEllipse(PointTable[k] + octaveRect.topLeft(), RadiusTable[k], RadiusTable[k]);
|
||||||
|
painter.setTransform(QTransform().translate(
|
||||||
|
PointTable[k].x() + octaveRect.left() - 13, PointTable[k].y() + octaveRect.top() - 20).rotate(-90.0));
|
||||||
|
painter.drawStaticText(QPointF{}, m_keyTexts[keyIdx]);
|
||||||
|
painter.setTransform(QTransform());
|
||||||
|
}
|
||||||
|
|
||||||
|
void KeymapView::paintEvent(QPaintEvent* ev)
|
||||||
|
{
|
||||||
|
QPainter painter(this);
|
||||||
|
painter.setRenderHint(QPainter::Antialiasing);
|
||||||
|
|
||||||
|
const QColor* keyPalette = getEditor()->m_paintPalette;
|
||||||
|
|
||||||
|
qreal deviceRatio = devicePixelRatioF();
|
||||||
|
qreal penWidth = std::max(std::floor(deviceRatio), 1.0) / deviceRatio;
|
||||||
|
|
||||||
|
painter.setFont(m_keyFont);
|
||||||
|
int kbY = height() / 2 - 100;
|
||||||
|
for (int o = 0; o < 10; ++o)
|
||||||
|
{
|
||||||
|
QRect thisRect(o * 280, kbY, 280, 200);
|
||||||
|
if (ev->rect().intersects(thisRect))
|
||||||
|
{
|
||||||
|
m_octaveRenderer.render(&painter, thisRect);
|
||||||
|
for (int k = 0; k < 12; ++k)
|
||||||
|
drawKey(painter, thisRect, penWidth, keyPalette, o, k);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
QRect thisRect(2800, kbY, 202, 200);
|
||||||
|
if (ev->rect().intersects(thisRect))
|
||||||
|
{
|
||||||
|
m_lastOctaveRenderer.render(&painter, thisRect);
|
||||||
|
for (int k = 0; k < 8; ++k)
|
||||||
|
drawKey(painter, thisRect, penWidth, keyPalette, 10, k);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void KeymapView::mousePressEvent(QMouseEvent* ev)
|
||||||
|
{
|
||||||
|
mouseMoveEvent(ev);
|
||||||
|
}
|
||||||
|
|
||||||
|
int KeymapView::getKey(const QPoint& localPos) const
|
||||||
|
{
|
||||||
|
QPointF localPoint = m_widgetToSvg.map(localPos);
|
||||||
|
for (int i = 0; i < 5; ++i)
|
||||||
|
if (m_sharp[i].contains(localPoint))
|
||||||
|
return SharpKeyNumbers[i];
|
||||||
|
for (int i = 0; i < 7; ++i)
|
||||||
|
if (m_natural[i].contains(localPoint))
|
||||||
|
return NaturalKeyNumbers[i];
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
void KeymapView::mouseMoveEvent(QMouseEvent* ev)
|
||||||
|
{
|
||||||
|
int octave = ev->x() / 280;
|
||||||
|
int key = getKey(ev->pos() - QPoint(octave * 280, height() / 2 - 100));
|
||||||
|
if (octave >= 0 && key >= 0)
|
||||||
|
getEditor()->touchKey(octave * 12 + key, ev->modifiers() & Qt::ShiftModifier);
|
||||||
|
}
|
||||||
|
|
||||||
|
void KeymapView::wheelEvent(QWheelEvent* event)
|
||||||
|
{
|
||||||
|
if (QScrollArea* scroll = qobject_cast<QScrollArea*>(parentWidget()->parentWidget()))
|
||||||
|
{
|
||||||
|
/* Send wheel event directly to the scroll bar */
|
||||||
|
QApplication::sendEvent(scroll->horizontalScrollBar(), event);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
KeymapView::KeymapView(QWidget* parent)
|
||||||
|
: QWidget(parent), m_octaveRenderer(QStringLiteral(":/bg/keyboard.svg")),
|
||||||
|
m_lastOctaveRenderer(QStringLiteral(":/bg/keyboard_last.svg"))
|
||||||
|
{
|
||||||
|
setMinimumWidth(3002);
|
||||||
|
|
||||||
|
int k = 0;
|
||||||
|
for (int i = 0; i < 11; ++i)
|
||||||
|
for (int j = 0; j < 12 && k < 128; ++j)
|
||||||
|
m_keyTexts[k++].setText(QStringLiteral("%1%2").arg(KeyStrings[j]).arg(i - 1));
|
||||||
|
m_keyFont.setPointSize(12);
|
||||||
|
std::fill(std::begin(m_keyPalettes), std::end(m_keyPalettes), -1);
|
||||||
|
|
||||||
|
for (int i = 0; i < 7; ++i)
|
||||||
|
if (m_octaveRenderer.elementExists(NaturalKeyNames[i]))
|
||||||
|
m_natural[i] = m_octaveRenderer.matrixForElement(NaturalKeyNames[i]).
|
||||||
|
mapRect(m_octaveRenderer.boundsOnElement(NaturalKeyNames[i]));
|
||||||
|
|
||||||
|
for (int i = 0; i < 5; ++i)
|
||||||
|
if (m_octaveRenderer.elementExists(SharpKeyNames[i]))
|
||||||
|
m_sharp[i] = m_octaveRenderer.matrixForElement(SharpKeyNames[i]).
|
||||||
|
mapRect(m_octaveRenderer.boundsOnElement(SharpKeyNames[i]));
|
||||||
|
|
||||||
|
m_widgetToSvg = RectToRect(QRect(0, 0, 280, 200), m_octaveRenderer.viewBoxF());
|
||||||
|
}
|
||||||
|
|
||||||
|
KeymapEditor* KeymapControls::getEditor() const
|
||||||
|
{
|
||||||
|
return qobject_cast<KeymapEditor*>(parentWidget());
|
||||||
|
}
|
||||||
|
|
||||||
|
void KeymapControls::setPaintIdx(int idx)
|
||||||
|
{
|
||||||
|
QPalette palette = m_paintButton->palette();
|
||||||
|
if (idx < 0)
|
||||||
|
{
|
||||||
|
palette.setColor(QPalette::Background, QWidget::palette().color(QPalette::Background));
|
||||||
|
palette.setColor(QPalette::Button, QWidget::palette().color(QPalette::Button));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
const QColor* keyPalette = getEditor()->m_paintPalette;
|
||||||
|
palette.setColor(QPalette::Background, keyPalette[idx]);
|
||||||
|
palette.setColor(QPalette::Button, keyPalette[idx].darker(300));
|
||||||
|
}
|
||||||
|
m_paintButton->setPalette(palette);
|
||||||
|
}
|
||||||
|
|
||||||
|
void KeymapControls::setKeymap(const amuse::Keymap& km)
|
||||||
|
{
|
||||||
|
m_enableUpdate = false;
|
||||||
|
int idx = m_macro->collection()->indexOfId(km.macro.id);
|
||||||
|
m_macro->setCurrentIndex(idx + 1);
|
||||||
|
m_transpose->setValue(km.transpose);
|
||||||
|
if (km.pan == -128)
|
||||||
|
{
|
||||||
|
m_pan->setDisabled(true);
|
||||||
|
m_pan->setValue(true);
|
||||||
|
m_surround->setChecked(true);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
m_pan->setEnabled(true);
|
||||||
|
m_pan->setValue(km.pan);
|
||||||
|
m_surround->setChecked(false);
|
||||||
|
}
|
||||||
|
m_prioOffset->setValue(km.prioOffset);
|
||||||
|
m_enableUpdate = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void KeymapControls::loadData(ProjectModel::KeymapNode* node)
|
||||||
|
{
|
||||||
|
m_enableUpdate = false;
|
||||||
|
m_macro->setCollection(g_MainWindow->projectModel()->getGroupNode(node)->
|
||||||
|
getCollectionOfType(ProjectModel::INode::Type::SoundMacro));
|
||||||
|
m_macro->setDisabled(false);
|
||||||
|
m_transpose->setDisabled(false);
|
||||||
|
m_transpose->setValue(0);
|
||||||
|
m_pan->setDisabled(false);
|
||||||
|
m_pan->setValue(64);
|
||||||
|
m_surround->setDisabled(false);
|
||||||
|
m_surround->setChecked(false);
|
||||||
|
m_prioOffset->setDisabled(false);
|
||||||
|
m_prioOffset->setValue(0);
|
||||||
|
m_paintButton->setDisabled(false);
|
||||||
|
m_paintButton->setPalette(palette());
|
||||||
|
m_enableUpdate = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void KeymapControls::unloadData()
|
||||||
|
{
|
||||||
|
m_enableUpdate = false;
|
||||||
|
m_macro->setCollection(nullptr);
|
||||||
|
m_macro->setDisabled(true);
|
||||||
|
m_transpose->setDisabled(true);
|
||||||
|
m_pan->setDisabled(true);
|
||||||
|
m_surround->setDisabled(true);
|
||||||
|
m_prioOffset->setDisabled(true);
|
||||||
|
m_paintButton->setDisabled(true);
|
||||||
|
m_paintButton->setPalette(palette());
|
||||||
|
m_enableUpdate = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void KeymapControls::controlChanged()
|
||||||
|
{
|
||||||
|
if (m_enableUpdate)
|
||||||
|
{
|
||||||
|
amuse::Keymap km;
|
||||||
|
km.macro.id = m_macro->currentIndex() == 0 ? amuse::SoundMacroId{} :
|
||||||
|
m_macro->collection()->idOfIndex(m_macro->currentIndex() - 1);
|
||||||
|
km.transpose = int8_t(m_transpose->value());
|
||||||
|
km.pan = int8_t(m_pan->value());
|
||||||
|
if (m_surround->isChecked())
|
||||||
|
{
|
||||||
|
km.pan = -128;
|
||||||
|
m_pan->setDisabled(true);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
m_pan->setEnabled(true);
|
||||||
|
}
|
||||||
|
km.prioOffset = int8_t(m_prioOffset->value());
|
||||||
|
getEditor()->touchControl(km);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void KeymapControls::paintButtonPressed()
|
||||||
|
{
|
||||||
|
KeymapEditor* editor = getEditor();
|
||||||
|
if (!editor->m_inPaint)
|
||||||
|
{
|
||||||
|
editor->setCursor(QCursor(QPixmap(QStringLiteral(":/icons/IconPaintbrush.svg")), 2, 30));
|
||||||
|
editor->m_inPaint = true;
|
||||||
|
m_paintButton->setDown(true);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
editor->unsetCursor();
|
||||||
|
editor->m_inPaint = false;
|
||||||
|
m_paintButton->setDown(false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
KeymapControls::KeymapControls(QWidget* parent)
|
||||||
|
: QFrame(parent)
|
||||||
|
{
|
||||||
|
setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Fixed);
|
||||||
|
setFixedHeight(100);
|
||||||
|
setFrameShape(QFrame::StyledPanel);
|
||||||
|
setFrameShadow(QFrame::Sunken);
|
||||||
|
setBackgroundRole(QPalette::Base);
|
||||||
|
setAutoFillBackground(true);
|
||||||
|
|
||||||
|
QPalette palette = QWidget::palette();
|
||||||
|
palette.setColor(QPalette::Base, palette.color(QPalette::Background));
|
||||||
|
|
||||||
|
QHBoxLayout* mainLayout = new QHBoxLayout;
|
||||||
|
|
||||||
|
QGridLayout* leftLayout = new QGridLayout;
|
||||||
|
|
||||||
|
leftLayout->addWidget(new QLabel(tr("SoundMacro")), 0, 0);
|
||||||
|
m_macro = new FieldProjectNode;
|
||||||
|
m_macro->setDisabled(true);
|
||||||
|
connect(m_macro, SIGNAL(currentIndexChanged(int)), this, SLOT(controlChanged()));
|
||||||
|
leftLayout->addWidget(m_macro, 1, 0);
|
||||||
|
|
||||||
|
leftLayout->addWidget(new QLabel(tr("Transpose")), 0, 1);
|
||||||
|
m_transpose = new QSpinBox;
|
||||||
|
m_transpose->setPalette(palette);
|
||||||
|
m_transpose->setDisabled(true);
|
||||||
|
m_transpose->setRange(-128, 127);
|
||||||
|
m_transpose->setToolTip(tr("Offset resulting MIDI note"));
|
||||||
|
connect(m_transpose, SIGNAL(valueChanged(int)), this, SLOT(controlChanged()));
|
||||||
|
leftLayout->addWidget(m_transpose, 1, 1);
|
||||||
|
|
||||||
|
leftLayout->addWidget(new QLabel(tr("Pan")), 0, 2);
|
||||||
|
m_pan = new QSpinBox;
|
||||||
|
m_pan->setPalette(palette);
|
||||||
|
m_pan->setDisabled(true);
|
||||||
|
m_pan->setRange(-127, 127);
|
||||||
|
m_pan->setToolTip(tr("Set initial pan"));
|
||||||
|
connect(m_pan, SIGNAL(valueChanged(int)), this, SLOT(controlChanged()));
|
||||||
|
leftLayout->addWidget(m_pan, 1, 2);
|
||||||
|
|
||||||
|
leftLayout->addWidget(new QLabel(tr("Surround")), 0, 3);
|
||||||
|
m_surround = new QCheckBox;
|
||||||
|
m_surround->setPalette(palette);
|
||||||
|
m_surround->setDisabled(true);
|
||||||
|
m_surround->setToolTip(tr("Initially play through surround channels"));
|
||||||
|
connect(m_surround, SIGNAL(stateChanged(int)), this, SLOT(controlChanged()));
|
||||||
|
leftLayout->addWidget(m_surround, 1, 3);
|
||||||
|
|
||||||
|
leftLayout->addWidget(new QLabel(tr("Prio Offset")), 0, 4);
|
||||||
|
m_prioOffset = new QSpinBox;
|
||||||
|
m_prioOffset->setPalette(palette);
|
||||||
|
m_prioOffset->setDisabled(true);
|
||||||
|
m_prioOffset->setRange(-128, 127);
|
||||||
|
m_prioOffset->setToolTip(tr("Offset resulting priority"));
|
||||||
|
connect(m_prioOffset, SIGNAL(valueChanged(int)), this, SLOT(controlChanged()));
|
||||||
|
leftLayout->addWidget(m_prioOffset, 1, 4);
|
||||||
|
|
||||||
|
leftLayout->setColumnMinimumWidth(0, 200);
|
||||||
|
leftLayout->setColumnMinimumWidth(1, 75);
|
||||||
|
leftLayout->setColumnMinimumWidth(2, 75);
|
||||||
|
leftLayout->setColumnMinimumWidth(3, 50);
|
||||||
|
leftLayout->setColumnMinimumWidth(4, 75);
|
||||||
|
leftLayout->setRowMinimumHeight(0, 22);
|
||||||
|
leftLayout->setRowMinimumHeight(1, 37);
|
||||||
|
leftLayout->setContentsMargins(10, 6, 0, 14);
|
||||||
|
|
||||||
|
QVBoxLayout* rightLayout = new QVBoxLayout;
|
||||||
|
|
||||||
|
m_paintButton = new PaintButton;
|
||||||
|
m_paintButton->setDisabled(true);
|
||||||
|
connect(m_paintButton, SIGNAL(pressed()), this, SLOT(paintButtonPressed()));
|
||||||
|
rightLayout->addWidget(m_paintButton);
|
||||||
|
rightLayout->setContentsMargins(0, 0, 10, 0);
|
||||||
|
|
||||||
|
mainLayout->addLayout(leftLayout);
|
||||||
|
mainLayout->addStretch(1);
|
||||||
|
mainLayout->addLayout(rightLayout);
|
||||||
|
setLayout(mainLayout);
|
||||||
|
}
|
||||||
|
|
||||||
|
void KeymapEditor::_touch()
|
||||||
|
{
|
||||||
|
if (m_controlKeymap.macro.id == 0xffff)
|
||||||
|
m_controls->setPaintIdx(-1);
|
||||||
|
else
|
||||||
|
m_controls->setPaintIdx(getConfigIdx(m_controlKeymap.configKey()));
|
||||||
|
}
|
||||||
|
|
||||||
|
void KeymapEditor::touchKey(int key, bool bulk)
|
||||||
|
{
|
||||||
|
if (m_inPaint)
|
||||||
|
{
|
||||||
|
if (bulk)
|
||||||
|
{
|
||||||
|
uint64_t refKey = (*m_kmView->m_node->m_obj)[key].configKey();
|
||||||
|
for (int i = 0; i < 128; ++i)
|
||||||
|
{
|
||||||
|
amuse::Keymap& km = (*m_kmView->m_node->m_obj)[i];
|
||||||
|
if (km.configKey() != refKey)
|
||||||
|
continue;
|
||||||
|
if (km.macro.id != 0xffff)
|
||||||
|
deallocateConfigIdx(km.configKey());
|
||||||
|
km = m_controlKeymap;
|
||||||
|
if (km.macro.id == 0xffff)
|
||||||
|
m_kmView->m_keyPalettes[i] = -1;
|
||||||
|
else
|
||||||
|
m_kmView->m_keyPalettes[i] = allocateConfigIdx(km.configKey());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
amuse::Keymap& km = (*m_kmView->m_node->m_obj)[key];
|
||||||
|
if (km.macro.id != 0xffff)
|
||||||
|
deallocateConfigIdx(km.configKey());
|
||||||
|
km = m_controlKeymap;
|
||||||
|
if (km.macro.id == 0xffff)
|
||||||
|
m_kmView->m_keyPalettes[key] = -1;
|
||||||
|
else
|
||||||
|
m_kmView->m_keyPalettes[key] = allocateConfigIdx(km.configKey());
|
||||||
|
}
|
||||||
|
|
||||||
|
m_kmView->update();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
amuse::Keymap& km = (*m_kmView->m_node->m_obj)[key];
|
||||||
|
m_controlKeymap = km;
|
||||||
|
m_controls->setKeymap(km);
|
||||||
|
_touch();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void KeymapEditor::touchControl(const amuse::Keymap& km)
|
||||||
|
{
|
||||||
|
m_controlKeymap = km;
|
||||||
|
_touch();
|
||||||
|
}
|
||||||
|
|
||||||
|
int KeymapEditor::allocateConfigIdx(uint64_t key)
|
||||||
|
{
|
||||||
|
auto search = m_configToIdx.find(key);
|
||||||
|
if (search != m_configToIdx.end())
|
||||||
|
{
|
||||||
|
++search->second.second;
|
||||||
|
return search->second.first;
|
||||||
|
}
|
||||||
|
for (int i = 0; i < 129; ++i)
|
||||||
|
if (!m_idxBitmap[i])
|
||||||
|
{
|
||||||
|
m_configToIdx[key] = std::make_pair(i, 1);
|
||||||
|
m_idxBitmap.set(i);
|
||||||
|
return i;
|
||||||
|
}
|
||||||
|
Q_UNREACHABLE();
|
||||||
|
}
|
||||||
|
|
||||||
|
void KeymapEditor::deallocateConfigIdx(uint64_t key)
|
||||||
|
{
|
||||||
|
auto search = m_configToIdx.find(key);
|
||||||
|
if (search != m_configToIdx.end())
|
||||||
|
{
|
||||||
|
--search->second.second;
|
||||||
|
if (search->second.second == 0)
|
||||||
|
{
|
||||||
|
m_idxBitmap.reset(search->second.first);
|
||||||
|
m_configToIdx.erase(search);
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
Q_UNREACHABLE();
|
||||||
|
}
|
||||||
|
|
||||||
|
int KeymapEditor::getConfigIdx(uint64_t key) const
|
||||||
|
{
|
||||||
|
auto search = m_configToIdx.find(key);
|
||||||
|
if (search != m_configToIdx.end())
|
||||||
|
return search->second.first;
|
||||||
|
for (int i = 0; i < 129; ++i)
|
||||||
|
if (!m_idxBitmap[i])
|
||||||
|
return i;
|
||||||
|
Q_UNREACHABLE();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool KeymapEditor::loadData(ProjectModel::KeymapNode* node)
|
||||||
|
{
|
||||||
|
if (m_kmView->m_node.get() != node)
|
||||||
|
{
|
||||||
|
m_configToIdx.clear();
|
||||||
|
m_idxBitmap.reset();
|
||||||
|
|
||||||
|
for (int i = 0; i < 128; ++i)
|
||||||
|
{
|
||||||
|
amuse::Keymap& km = (*node->m_obj)[i];
|
||||||
|
if (km.macro.id == 0xffff)
|
||||||
|
m_kmView->m_keyPalettes[i] = -1;
|
||||||
|
else
|
||||||
|
m_kmView->m_keyPalettes[i] = allocateConfigIdx(km.configKey());
|
||||||
|
}
|
||||||
|
|
||||||
|
m_controlKeymap = amuse::Keymap();
|
||||||
|
m_kmView->loadData(node);
|
||||||
|
m_controls->loadData(node);
|
||||||
|
}
|
||||||
|
|
||||||
|
m_inPaint = false;
|
||||||
|
m_controls->m_paintButton->setDown(false);
|
||||||
|
unsetCursor();
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void KeymapEditor::unloadData()
|
||||||
|
{
|
||||||
|
m_configToIdx.clear();
|
||||||
|
m_idxBitmap.reset();
|
||||||
|
m_kmView->unloadData();
|
||||||
|
m_controls->unloadData();
|
||||||
|
|
||||||
|
m_inPaint = false;
|
||||||
|
m_controls->m_paintButton->setDown(false);
|
||||||
|
unsetCursor();
|
||||||
|
}
|
||||||
|
|
||||||
|
ProjectModel::INode* KeymapEditor::currentNode() const
|
||||||
|
{
|
||||||
|
return m_kmView->currentNode();
|
||||||
|
}
|
||||||
|
|
||||||
|
void KeymapEditor::keyPressEvent(QKeyEvent* event)
|
||||||
|
{
|
||||||
|
if (event->key() == Qt::Key_Escape)
|
||||||
|
{
|
||||||
|
if (m_inPaint)
|
||||||
|
{
|
||||||
|
m_inPaint = false;
|
||||||
|
m_controls->m_paintButton->setDown(false);
|
||||||
|
unsetCursor();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
KeymapEditor::KeymapEditor(QWidget* parent)
|
||||||
|
: EditorWidget(parent), m_scrollArea(new QScrollArea),
|
||||||
|
m_kmView(new KeymapView), m_controls(new KeymapControls)
|
||||||
|
{
|
||||||
|
|
||||||
|
int k = 0;
|
||||||
|
for (int i = 0; i < 13; ++i)
|
||||||
|
for (int j = 0; j < 10 && k < 129; ++j)
|
||||||
|
m_paintPalette[k++].setHsv(HueTable[j], SaturationTable[i], ValueTable[i]);
|
||||||
|
|
||||||
|
m_scrollArea->setWidget(m_kmView);
|
||||||
|
m_scrollArea->setWidgetResizable(true);
|
||||||
|
|
||||||
|
QVBoxLayout* layout = new QVBoxLayout;
|
||||||
|
layout->setContentsMargins(QMargins());
|
||||||
|
layout->setSpacing(1);
|
||||||
|
layout->addWidget(m_scrollArea);
|
||||||
|
layout->addWidget(m_controls);
|
||||||
|
setLayout(layout);
|
||||||
|
}
|
||||||
109
Editor/KeymapEditor.hpp
Normal file
@@ -0,0 +1,109 @@
|
|||||||
|
#ifndef AMUSE_KEYMAP_EDITOR_HPP
|
||||||
|
#define AMUSE_KEYMAP_EDITOR_HPP
|
||||||
|
|
||||||
|
#include "EditorWidget.hpp"
|
||||||
|
#include <QFrame>
|
||||||
|
#include <QLabel>
|
||||||
|
#include <QStaticText>
|
||||||
|
#include <QSpinBox>
|
||||||
|
#include <QPushButton>
|
||||||
|
#include <QSvgRenderer>
|
||||||
|
#include <QScrollArea>
|
||||||
|
#include <QCheckBox>
|
||||||
|
#include <bitset>
|
||||||
|
|
||||||
|
class KeymapEditor;
|
||||||
|
|
||||||
|
class PaintButton : public QPushButton
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
public:
|
||||||
|
explicit PaintButton(QWidget* parent = Q_NULLPTR);
|
||||||
|
void mouseReleaseEvent(QMouseEvent* event) { event->ignore(); }
|
||||||
|
void mouseMoveEvent(QMouseEvent* event) { event->ignore(); }
|
||||||
|
void focusOutEvent(QFocusEvent* event) { event->ignore(); }
|
||||||
|
void keyPressEvent(QKeyEvent* event) { event->ignore(); }
|
||||||
|
};
|
||||||
|
|
||||||
|
class KeymapView : public QWidget
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
friend class KeymapControls;
|
||||||
|
friend class KeymapEditor;
|
||||||
|
amuse::ObjToken<ProjectModel::KeymapNode> m_node;
|
||||||
|
QSvgRenderer m_octaveRenderer;
|
||||||
|
QSvgRenderer m_lastOctaveRenderer;
|
||||||
|
QRectF m_natural[7];
|
||||||
|
QRectF m_sharp[5];
|
||||||
|
QTransform m_widgetToSvg;
|
||||||
|
QFont m_keyFont;
|
||||||
|
QStaticText m_keyTexts[128];
|
||||||
|
int m_keyPalettes[128];
|
||||||
|
KeymapEditor* getEditor() const;
|
||||||
|
int getKey(const QPoint& localPos) const;
|
||||||
|
void drawKey(QPainter& painter, const QRect& octaveRect, qreal penWidth,
|
||||||
|
const QColor* keyPalette, int o, int k) const;
|
||||||
|
public:
|
||||||
|
explicit KeymapView(QWidget* parent = Q_NULLPTR);
|
||||||
|
void loadData(ProjectModel::KeymapNode* node);
|
||||||
|
void unloadData();
|
||||||
|
ProjectModel::INode* currentNode() const;
|
||||||
|
|
||||||
|
void paintEvent(QPaintEvent* ev);
|
||||||
|
void mousePressEvent(QMouseEvent* ev);
|
||||||
|
void mouseMoveEvent(QMouseEvent* ev);
|
||||||
|
void wheelEvent(QWheelEvent* event);
|
||||||
|
};
|
||||||
|
|
||||||
|
class KeymapControls : public QFrame
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
friend class KeymapView;
|
||||||
|
friend class KeymapEditor;
|
||||||
|
FieldProjectNode* m_macro;
|
||||||
|
QSpinBox* m_transpose;
|
||||||
|
QSpinBox* m_pan;
|
||||||
|
QCheckBox* m_surround;
|
||||||
|
QSpinBox* m_prioOffset;
|
||||||
|
PaintButton* m_paintButton;
|
||||||
|
bool m_enableUpdate = true;
|
||||||
|
KeymapEditor* getEditor() const;
|
||||||
|
void setPaintIdx(int idx);
|
||||||
|
void setKeymap(const amuse::Keymap& km);
|
||||||
|
public:
|
||||||
|
explicit KeymapControls(QWidget* parent = Q_NULLPTR);
|
||||||
|
void loadData(ProjectModel::KeymapNode* node);
|
||||||
|
void unloadData();
|
||||||
|
public slots:
|
||||||
|
void controlChanged();
|
||||||
|
void paintButtonPressed();
|
||||||
|
};
|
||||||
|
|
||||||
|
class KeymapEditor : public EditorWidget
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
friend class KeymapView;
|
||||||
|
friend class KeymapControls;
|
||||||
|
QScrollArea* m_scrollArea;
|
||||||
|
KeymapView* m_kmView;
|
||||||
|
KeymapControls* m_controls;
|
||||||
|
QColor m_paintPalette[129];
|
||||||
|
amuse::Keymap m_controlKeymap;
|
||||||
|
std::unordered_map<uint64_t, std::pair<int, int>> m_configToIdx;
|
||||||
|
std::bitset<129> m_idxBitmap;
|
||||||
|
bool m_inPaint = false;
|
||||||
|
void _touch();
|
||||||
|
void touchKey(int key, bool bulk = false);
|
||||||
|
void touchControl(const amuse::Keymap& km);
|
||||||
|
int allocateConfigIdx(uint64_t key);
|
||||||
|
void deallocateConfigIdx(uint64_t key);
|
||||||
|
int getConfigIdx(uint64_t key) const;
|
||||||
|
public:
|
||||||
|
explicit KeymapEditor(QWidget* parent = Q_NULLPTR);
|
||||||
|
bool loadData(ProjectModel::KeymapNode* node);
|
||||||
|
void unloadData();
|
||||||
|
ProjectModel::INode* currentNode() const;
|
||||||
|
void keyPressEvent(QKeyEvent* event);
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif //AMUSE_KEYMAP_EDITOR_HPP
|
||||||
682
Editor/LayersEditor.cpp
Normal file
@@ -0,0 +1,682 @@
|
|||||||
|
#include "LayersEditor.hpp"
|
||||||
|
#include "MainWindow.hpp"
|
||||||
|
#include <QVBoxLayout>
|
||||||
|
#include <QScrollBar>
|
||||||
|
#include <QMimeData>
|
||||||
|
|
||||||
|
class LayerDataChangeUndoCommand : public EditorUndoCommand
|
||||||
|
{
|
||||||
|
QModelIndex m_index;
|
||||||
|
int m_undoVal, m_redoVal;
|
||||||
|
bool m_undid = false;
|
||||||
|
public:
|
||||||
|
explicit LayerDataChangeUndoCommand(ProjectModel::LayersNode* node, const QString& text,
|
||||||
|
QModelIndex index, int redoVal)
|
||||||
|
: EditorUndoCommand(node, text), m_index(index), m_redoVal(redoVal) {}
|
||||||
|
void undo()
|
||||||
|
{
|
||||||
|
m_undid = true;
|
||||||
|
amuse::LayerMapping& layer = (*static_cast<ProjectModel::LayersNode*>(m_node.get())->m_obj)[m_index.row()];
|
||||||
|
|
||||||
|
switch (m_index.column())
|
||||||
|
{
|
||||||
|
case 0:
|
||||||
|
layer.macro.id = m_undoVal;
|
||||||
|
break;
|
||||||
|
case 1:
|
||||||
|
layer.keyLo = m_undoVal;
|
||||||
|
break;
|
||||||
|
case 2:
|
||||||
|
layer.keyHi = m_undoVal;
|
||||||
|
break;
|
||||||
|
case 3:
|
||||||
|
layer.transpose = m_undoVal;
|
||||||
|
break;
|
||||||
|
case 4:
|
||||||
|
layer.volume = m_undoVal;
|
||||||
|
break;
|
||||||
|
case 5:
|
||||||
|
layer.prioOffset = m_undoVal;
|
||||||
|
break;
|
||||||
|
case 6:
|
||||||
|
layer.span = m_undoVal;
|
||||||
|
break;
|
||||||
|
case 7:
|
||||||
|
layer.pan = m_undoVal;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
EditorUndoCommand::undo();
|
||||||
|
}
|
||||||
|
void redo()
|
||||||
|
{
|
||||||
|
amuse::LayerMapping& layer = (*static_cast<ProjectModel::LayersNode*>(m_node.get())->m_obj)[m_index.row()];
|
||||||
|
|
||||||
|
switch (m_index.column())
|
||||||
|
{
|
||||||
|
case 0:
|
||||||
|
m_undoVal = layer.macro.id;
|
||||||
|
layer.macro.id = m_redoVal;
|
||||||
|
break;
|
||||||
|
case 1:
|
||||||
|
m_undoVal = layer.keyLo;
|
||||||
|
layer.keyLo = m_redoVal;
|
||||||
|
break;
|
||||||
|
case 2:
|
||||||
|
m_undoVal = layer.keyHi;
|
||||||
|
layer.keyHi = m_redoVal;
|
||||||
|
break;
|
||||||
|
case 3:
|
||||||
|
m_undoVal = layer.transpose;
|
||||||
|
layer.transpose = m_redoVal;
|
||||||
|
break;
|
||||||
|
case 4:
|
||||||
|
m_undoVal = layer.volume;
|
||||||
|
layer.volume = m_redoVal;
|
||||||
|
break;
|
||||||
|
case 5:
|
||||||
|
m_undoVal = layer.prioOffset;
|
||||||
|
layer.prioOffset = m_redoVal;
|
||||||
|
break;
|
||||||
|
case 6:
|
||||||
|
m_undoVal = layer.span;
|
||||||
|
layer.span = m_redoVal;
|
||||||
|
break;
|
||||||
|
case 7:
|
||||||
|
m_undoVal = layer.pan;
|
||||||
|
layer.pan = m_redoVal;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (m_undid)
|
||||||
|
EditorUndoCommand::redo();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
SoundMacroDelegate::SoundMacroDelegate(QObject* parent)
|
||||||
|
: BaseObjectDelegate(parent) {}
|
||||||
|
|
||||||
|
ProjectModel::INode* SoundMacroDelegate::getNode(const QAbstractItemModel* __model, const QModelIndex& index) const
|
||||||
|
{
|
||||||
|
const LayersModel* model = static_cast<const LayersModel*>(__model);
|
||||||
|
const amuse::LayerMapping& layer = (*model->m_node->m_obj)[index.row()];
|
||||||
|
ProjectModel::GroupNode* group = g_MainWindow->projectModel()->getGroupNode(model->m_node.get());
|
||||||
|
ProjectModel::CollectionNode* smColl = group->getCollectionOfType(ProjectModel::INode::Type::SoundMacro);
|
||||||
|
return smColl->nodeOfId(layer.macro.id);
|
||||||
|
}
|
||||||
|
|
||||||
|
QWidget* SoundMacroDelegate::createEditor(QWidget* parent, const QStyleOptionViewItem& option, const QModelIndex& index) const
|
||||||
|
{
|
||||||
|
const LayersModel* model = static_cast<const LayersModel*>(index.model());
|
||||||
|
ProjectModel::GroupNode* group = g_MainWindow->projectModel()->getGroupNode(model->m_node.get());
|
||||||
|
EditorFieldProjectNode* cb =
|
||||||
|
new EditorFieldProjectNode(group->getCollectionOfType(ProjectModel::INode::Type::SoundMacro), parent);
|
||||||
|
connect(cb, SIGNAL(currentIndexChanged(int)), this, SLOT(smIndexChanged()));
|
||||||
|
return cb;
|
||||||
|
}
|
||||||
|
|
||||||
|
void SoundMacroDelegate::setEditorData(QWidget* editor, const QModelIndex& index) const
|
||||||
|
{
|
||||||
|
const LayersModel* model = static_cast<const LayersModel*>(index.model());
|
||||||
|
const amuse::LayerMapping& layer = (*model->m_node->m_obj)[index.row()];
|
||||||
|
ProjectModel::GroupNode* group = g_MainWindow->projectModel()->getGroupNode(model->m_node.get());
|
||||||
|
ProjectModel::CollectionNode* smColl = group->getCollectionOfType(ProjectModel::INode::Type::SoundMacro);
|
||||||
|
static_cast<EditorFieldProjectNode*>(editor)->setCurrentIndex(smColl->indexOfId(layer.macro.id) + 1);
|
||||||
|
if (static_cast<EditorFieldProjectNode*>(editor)->shouldPopupOpen())
|
||||||
|
QApplication::postEvent(editor, new QEvent(QEvent::User));
|
||||||
|
}
|
||||||
|
|
||||||
|
void SoundMacroDelegate::setModelData(QWidget* editor, QAbstractItemModel* m, const QModelIndex& index) const
|
||||||
|
{
|
||||||
|
const LayersModel* model = static_cast<const LayersModel*>(m);
|
||||||
|
amuse::LayerMapping& layer = (*model->m_node->m_obj)[index.row()];
|
||||||
|
ProjectModel::GroupNode* group = g_MainWindow->projectModel()->getGroupNode(model->m_node.get());
|
||||||
|
ProjectModel::CollectionNode* smColl = group->getCollectionOfType(ProjectModel::INode::Type::SoundMacro);
|
||||||
|
int idx = static_cast<EditorFieldProjectNode*>(editor)->currentIndex();
|
||||||
|
amuse::SoundMacroId id;
|
||||||
|
if (idx != 0)
|
||||||
|
id = smColl->idOfIndex(idx - 1);
|
||||||
|
if (layer.macro.id == id)
|
||||||
|
return;
|
||||||
|
g_MainWindow->pushUndoCommand(new LayerDataChangeUndoCommand(model->m_node.get(),
|
||||||
|
tr("Change %1").arg(m->headerData(0, Qt::Horizontal).toString()), index, id.id));
|
||||||
|
emit m->dataChanged(index, index, {Qt::DisplayRole, Qt::EditRole});
|
||||||
|
}
|
||||||
|
|
||||||
|
void SoundMacroDelegate::smIndexChanged()
|
||||||
|
{
|
||||||
|
emit commitData(static_cast<QWidget*>(sender()));
|
||||||
|
}
|
||||||
|
|
||||||
|
void LayersModel::loadData(ProjectModel::LayersNode* node)
|
||||||
|
{
|
||||||
|
beginResetModel();
|
||||||
|
m_node = node;
|
||||||
|
endResetModel();
|
||||||
|
}
|
||||||
|
|
||||||
|
void LayersModel::unloadData()
|
||||||
|
{
|
||||||
|
beginResetModel();
|
||||||
|
m_node.reset();
|
||||||
|
endResetModel();
|
||||||
|
}
|
||||||
|
|
||||||
|
int LayersModel::rowCount(const QModelIndex& parent) const
|
||||||
|
{
|
||||||
|
if (parent.isValid())
|
||||||
|
return 0;
|
||||||
|
if (!m_node)
|
||||||
|
return 0;
|
||||||
|
return int(m_node->m_obj->size()) + 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
int LayersModel::columnCount(const QModelIndex& parent) const
|
||||||
|
{
|
||||||
|
if (parent.isValid())
|
||||||
|
return 0;
|
||||||
|
return 8;
|
||||||
|
}
|
||||||
|
|
||||||
|
QVariant LayersModel::data(const QModelIndex& index, int role) const
|
||||||
|
{
|
||||||
|
if (!m_node)
|
||||||
|
return QVariant();
|
||||||
|
if (index.row() == m_node->m_obj->size())
|
||||||
|
return QVariant();
|
||||||
|
const amuse::LayerMapping& layer = (*m_node->m_obj)[index.row()];
|
||||||
|
|
||||||
|
if (role == Qt::DisplayRole || role == Qt::EditRole)
|
||||||
|
{
|
||||||
|
switch (index.column())
|
||||||
|
{
|
||||||
|
case 0:
|
||||||
|
{
|
||||||
|
ProjectModel::GroupNode* group = g_MainWindow->projectModel()->getGroupNode(m_node.get());
|
||||||
|
ProjectModel::CollectionNode* smColl = group->getCollectionOfType(ProjectModel::INode::Type::SoundMacro);
|
||||||
|
if (ProjectModel::BasePoolObjectNode* node = smColl->nodeOfId(layer.macro.id))
|
||||||
|
return node->text();
|
||||||
|
return QVariant();
|
||||||
|
}
|
||||||
|
case 1:
|
||||||
|
return layer.keyLo;
|
||||||
|
case 2:
|
||||||
|
return layer.keyHi;
|
||||||
|
case 3:
|
||||||
|
return layer.transpose;
|
||||||
|
case 4:
|
||||||
|
return layer.volume;
|
||||||
|
case 5:
|
||||||
|
return layer.prioOffset;
|
||||||
|
case 6:
|
||||||
|
return layer.span;
|
||||||
|
case 7:
|
||||||
|
return layer.pan;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return QVariant();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool LayersModel::setData(const QModelIndex& index, const QVariant& value, int role)
|
||||||
|
{
|
||||||
|
if (!m_node || role != Qt::EditRole)
|
||||||
|
return false;
|
||||||
|
const amuse::LayerMapping& layer = (*m_node->m_obj)[index.row()];
|
||||||
|
|
||||||
|
switch (index.column())
|
||||||
|
{
|
||||||
|
case 0:
|
||||||
|
if (layer.macro.id == value.toInt())
|
||||||
|
return false;
|
||||||
|
break;
|
||||||
|
case 1:
|
||||||
|
if (layer.keyLo == value.toInt())
|
||||||
|
return false;
|
||||||
|
break;
|
||||||
|
case 2:
|
||||||
|
if (layer.keyHi == value.toInt())
|
||||||
|
return false;
|
||||||
|
break;
|
||||||
|
case 3:
|
||||||
|
if (layer.transpose == value.toInt())
|
||||||
|
return false;
|
||||||
|
break;
|
||||||
|
case 4:
|
||||||
|
if (layer.volume == value.toInt())
|
||||||
|
return false;
|
||||||
|
break;
|
||||||
|
case 5:
|
||||||
|
if (layer.prioOffset == value.toInt())
|
||||||
|
return false;
|
||||||
|
break;
|
||||||
|
case 6:
|
||||||
|
if (layer.span == value.toInt())
|
||||||
|
return false;
|
||||||
|
break;
|
||||||
|
case 7:
|
||||||
|
if (layer.pan == value.toInt())
|
||||||
|
return false;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
g_MainWindow->pushUndoCommand(new LayerDataChangeUndoCommand(m_node.get(),
|
||||||
|
tr("Change %1").arg(headerData(index.column(), Qt::Horizontal).toString()), index, value.toInt()));
|
||||||
|
emit dataChanged(index, index, {Qt::DisplayRole, Qt::EditRole});
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
QVariant LayersModel::headerData(int section, Qt::Orientation orientation, int role) const
|
||||||
|
{
|
||||||
|
if (orientation == Qt::Horizontal && role == Qt::DisplayRole)
|
||||||
|
{
|
||||||
|
switch (section)
|
||||||
|
{
|
||||||
|
case 0:
|
||||||
|
return tr("SoundMacro");
|
||||||
|
case 1:
|
||||||
|
return tr("Key Lo");
|
||||||
|
case 2:
|
||||||
|
return tr("Key Hi");
|
||||||
|
case 3:
|
||||||
|
return tr("Transpose");
|
||||||
|
case 4:
|
||||||
|
return tr("Volume");
|
||||||
|
case 5:
|
||||||
|
return tr("Prio Off");
|
||||||
|
case 6:
|
||||||
|
return tr("Span");
|
||||||
|
case 7:
|
||||||
|
return tr("Pan");
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return QVariant();
|
||||||
|
}
|
||||||
|
|
||||||
|
Qt::ItemFlags LayersModel::flags(const QModelIndex& index) const
|
||||||
|
{
|
||||||
|
if (!index.isValid())
|
||||||
|
return Qt::NoItemFlags;
|
||||||
|
if (index.row() == m_node->m_obj->size())
|
||||||
|
return Qt::NoItemFlags;
|
||||||
|
return Qt::ItemIsSelectable | Qt::ItemIsEnabled | Qt::ItemIsEditable | Qt::ItemIsDragEnabled | Qt::ItemIsDropEnabled;
|
||||||
|
}
|
||||||
|
|
||||||
|
Qt::DropActions LayersModel::supportedDropActions() const
|
||||||
|
{
|
||||||
|
return Qt::MoveAction;
|
||||||
|
}
|
||||||
|
|
||||||
|
Qt::DropActions LayersModel::supportedDragActions() const
|
||||||
|
{
|
||||||
|
return Qt::MoveAction;
|
||||||
|
}
|
||||||
|
|
||||||
|
class LayerRowMoveCommand : public EditorUndoCommand
|
||||||
|
{
|
||||||
|
LayersTableView* m_view;
|
||||||
|
int m_undoPos, m_redoPos, m_count;
|
||||||
|
bool m_undid = false;
|
||||||
|
public:
|
||||||
|
explicit LayerRowMoveCommand(ProjectModel::LayersNode* node, const QString& text, LayersTableView* view,
|
||||||
|
int undoPos, int redoPos, int count)
|
||||||
|
: EditorUndoCommand(node, text), m_view(view), m_undoPos(undoPos), m_redoPos(redoPos), m_count(count) {}
|
||||||
|
void undo()
|
||||||
|
{
|
||||||
|
m_undid = true;
|
||||||
|
EditorUndoCommand::undo();
|
||||||
|
if (m_redoPos > m_undoPos)
|
||||||
|
m_view->model()->moveRows(QModelIndex(), m_redoPos - 1, m_count, QModelIndex(), m_undoPos);
|
||||||
|
else
|
||||||
|
m_view->model()->moveRows(QModelIndex(), m_redoPos, m_count, QModelIndex(), m_undoPos + 1);
|
||||||
|
}
|
||||||
|
void redo()
|
||||||
|
{
|
||||||
|
if (m_undid)
|
||||||
|
EditorUndoCommand::redo();
|
||||||
|
m_view->model()->moveRows(QModelIndex(), m_undoPos, m_count, QModelIndex(), m_redoPos);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
bool LayersModel::dropMimeData(const QMimeData* data, Qt::DropAction action,
|
||||||
|
int row, int column, const QModelIndex& parent)
|
||||||
|
{
|
||||||
|
// check if the action is supported
|
||||||
|
if (!data || action != Qt::MoveAction)
|
||||||
|
return false;
|
||||||
|
// check if the format is supported
|
||||||
|
QStringList types = mimeTypes();
|
||||||
|
if (types.isEmpty())
|
||||||
|
return false;
|
||||||
|
QString format = types.at(0);
|
||||||
|
if (!data->hasFormat(format))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
// decode and insert
|
||||||
|
QByteArray encoded = data->data(format);
|
||||||
|
QDataStream stream(&encoded, QIODevice::ReadOnly);
|
||||||
|
|
||||||
|
std::unordered_set<int> rows;
|
||||||
|
int lastRow = -1;
|
||||||
|
|
||||||
|
while (!stream.atEnd()) {
|
||||||
|
int r, c;
|
||||||
|
QMap<int, QVariant> v;
|
||||||
|
stream >> r >> c >> v;
|
||||||
|
rows.insert(r);
|
||||||
|
lastRow = r;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (lastRow == -1)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
int start = lastRow;
|
||||||
|
while (rows.find(start - 1) != rows.cend())
|
||||||
|
start -= 1;
|
||||||
|
int count = lastRow - start + 1;
|
||||||
|
while (rows.find(start + count) != rows.cend())
|
||||||
|
count += 1;
|
||||||
|
|
||||||
|
int dest = parent.row();
|
||||||
|
if (dest >= start)
|
||||||
|
{
|
||||||
|
if (dest - start < count)
|
||||||
|
return false;
|
||||||
|
dest += 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
g_MainWindow->pushUndoCommand(new LayerRowMoveCommand(m_node.get(),
|
||||||
|
count > 1 ? tr("Move Layers") : tr("Move Layer"),
|
||||||
|
&static_cast<LayersEditor*>(QObject::parent())->m_tableView, start, dest, count));
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
class LayerRowUndoCommand : public EditorUndoCommand
|
||||||
|
{
|
||||||
|
protected:
|
||||||
|
LayersTableView* m_view;
|
||||||
|
std::vector<std::pair<amuse::LayerMapping, int>> m_data;
|
||||||
|
bool m_undid = false;
|
||||||
|
void add()
|
||||||
|
{
|
||||||
|
m_view->selectionModel()->clearSelection();
|
||||||
|
for (const auto& p : m_data)
|
||||||
|
{
|
||||||
|
static_cast<LayersModel*>(m_view->model())->_insertRow(p.second, p.first);
|
||||||
|
m_view->setCurrentIndex(m_view->model()->index(p.second, 0));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
void del()
|
||||||
|
{
|
||||||
|
for (auto it = m_data.rbegin(); it != m_data.rend(); ++it)
|
||||||
|
{
|
||||||
|
it->first = static_cast<LayersModel*>(m_view->model())->_removeRow(it->second);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
void undo()
|
||||||
|
{
|
||||||
|
m_undid = true;
|
||||||
|
EditorUndoCommand::undo();
|
||||||
|
}
|
||||||
|
void redo()
|
||||||
|
{
|
||||||
|
if (m_undid)
|
||||||
|
EditorUndoCommand::redo();
|
||||||
|
}
|
||||||
|
public:
|
||||||
|
explicit LayerRowUndoCommand(ProjectModel::LayersNode* node, const QString& text, LayersTableView* view,
|
||||||
|
std::vector<std::pair<amuse::LayerMapping, int>>&& data)
|
||||||
|
: EditorUndoCommand(node, text), m_view(view), m_data(std::move(data)) {}
|
||||||
|
};
|
||||||
|
|
||||||
|
class LayerRowAddUndoCommand : public LayerRowUndoCommand
|
||||||
|
{
|
||||||
|
using base = LayerRowUndoCommand;
|
||||||
|
public:
|
||||||
|
explicit LayerRowAddUndoCommand(ProjectModel::LayersNode* node, const QString& text, LayersTableView* view,
|
||||||
|
std::vector<std::pair<amuse::LayerMapping, int>>&& data)
|
||||||
|
: LayerRowUndoCommand(node, text, view, std::move(data)) {}
|
||||||
|
void undo() { base::undo(); base::del(); }
|
||||||
|
void redo() { base::redo(); base::add(); }
|
||||||
|
};
|
||||||
|
|
||||||
|
class LayerRowDelUndoCommand : public LayerRowUndoCommand
|
||||||
|
{
|
||||||
|
using base = LayerRowUndoCommand;
|
||||||
|
public:
|
||||||
|
explicit LayerRowDelUndoCommand(ProjectModel::LayersNode* node, const QString& text, LayersTableView* view,
|
||||||
|
std::vector<std::pair<amuse::LayerMapping, int>>&& data)
|
||||||
|
: LayerRowUndoCommand(node, text, view, std::move(data)) {}
|
||||||
|
void undo() { base::undo(); base::add(); }
|
||||||
|
void redo() { base::redo(); base::del(); }
|
||||||
|
};
|
||||||
|
|
||||||
|
bool LayersModel::insertRows(int row, int count, const QModelIndex& parent)
|
||||||
|
{
|
||||||
|
if (!m_node)
|
||||||
|
return false;
|
||||||
|
beginInsertRows(parent, row, row + count - 1);
|
||||||
|
std::vector<amuse::LayerMapping>& layers = *m_node->m_obj;
|
||||||
|
layers.insert(layers.begin() + row, count, amuse::LayerMapping());
|
||||||
|
endInsertRows();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool LayersModel::moveRows(const QModelIndex& sourceParent, int sourceRow, int count,
|
||||||
|
const QModelIndex& destinationParent, int destinationChild)
|
||||||
|
{
|
||||||
|
if (!m_node)
|
||||||
|
return false;
|
||||||
|
bool moving = beginMoveRows(sourceParent, sourceRow, sourceRow + count - 1, destinationParent, destinationChild);
|
||||||
|
std::vector<amuse::LayerMapping>& layers = *m_node->m_obj;
|
||||||
|
if (destinationChild < sourceRow)
|
||||||
|
{
|
||||||
|
for (int i = 0; i < count; ++i)
|
||||||
|
{
|
||||||
|
amuse::LayerMapping tmp = std::move(layers[sourceRow]);
|
||||||
|
for (int j = sourceRow; j != destinationChild; --j)
|
||||||
|
layers[j] = std::move(layers[j - 1]);
|
||||||
|
layers[destinationChild] = std::move(tmp);
|
||||||
|
++sourceRow;
|
||||||
|
++destinationChild;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (destinationChild > sourceRow)
|
||||||
|
{
|
||||||
|
for (int i = 0; i < count; ++i)
|
||||||
|
{
|
||||||
|
amuse::LayerMapping tmp = std::move(layers[sourceRow]);
|
||||||
|
for (int j = sourceRow; j != destinationChild - 1; ++j)
|
||||||
|
layers[j] = std::move(layers[j + 1]);
|
||||||
|
layers[destinationChild - 1] = std::move(tmp);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (moving)
|
||||||
|
endMoveRows();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool LayersModel::removeRows(int row, int count, const QModelIndex& parent)
|
||||||
|
{
|
||||||
|
if (!m_node)
|
||||||
|
return false;
|
||||||
|
beginRemoveRows(parent, row, row + count - 1);
|
||||||
|
std::vector<amuse::LayerMapping>& layers = *m_node->m_obj;
|
||||||
|
layers.erase(layers.begin() + row, layers.begin() + row + count);
|
||||||
|
endRemoveRows();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void LayersModel::_insertRow(int row, const amuse::LayerMapping& data)
|
||||||
|
{
|
||||||
|
if (!m_node)
|
||||||
|
return;
|
||||||
|
beginInsertRows(QModelIndex(), row, row);
|
||||||
|
std::vector<amuse::LayerMapping>& layers = *m_node->m_obj;
|
||||||
|
layers.insert(layers.begin() + row, data);
|
||||||
|
endInsertRows();
|
||||||
|
}
|
||||||
|
|
||||||
|
amuse::LayerMapping LayersModel::_removeRow(int row)
|
||||||
|
{
|
||||||
|
if (!m_node)
|
||||||
|
return {};
|
||||||
|
beginRemoveRows(QModelIndex(), row, row);
|
||||||
|
std::vector<amuse::LayerMapping>& layers = *m_node->m_obj;
|
||||||
|
amuse::LayerMapping ret = layers[row];
|
||||||
|
layers.erase(layers.begin() + row);
|
||||||
|
endRemoveRows();
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
LayersModel::LayersModel(QObject* parent)
|
||||||
|
: QAbstractTableModel(parent)
|
||||||
|
{}
|
||||||
|
|
||||||
|
void LayersTableView::deleteSelection()
|
||||||
|
{
|
||||||
|
QModelIndexList list = selectionModel()->selectedRows();
|
||||||
|
if (list.isEmpty())
|
||||||
|
return;
|
||||||
|
std::vector<std::pair<amuse::LayerMapping, int>> data;
|
||||||
|
data.reserve(list.size());
|
||||||
|
for (QModelIndex idx : list)
|
||||||
|
data.push_back(std::make_pair(amuse::LayerMapping{}, idx.row()));
|
||||||
|
std::sort(data.begin(), data.end(), [](const auto& a, const auto& b) { return a.second < b.second; });
|
||||||
|
g_MainWindow->pushUndoCommand(
|
||||||
|
new LayerRowDelUndoCommand(static_cast<LayersModel*>(model())->m_node.get(),
|
||||||
|
data.size() > 1 ? tr("Delete Layers") : tr("Delete Layer"), this, std::move(data)));
|
||||||
|
}
|
||||||
|
|
||||||
|
void LayersTableView::setModel(QAbstractItemModel* model)
|
||||||
|
{
|
||||||
|
QTableView::setModel(model);
|
||||||
|
horizontalHeader()->setMinimumSectionSize(75);
|
||||||
|
horizontalHeader()->setSectionResizeMode(0, QHeaderView::Stretch);
|
||||||
|
horizontalHeader()->setSectionResizeMode(1, QHeaderView::Fixed);
|
||||||
|
horizontalHeader()->resizeSection(1, 75);
|
||||||
|
horizontalHeader()->setSectionResizeMode(2, QHeaderView::Fixed);
|
||||||
|
horizontalHeader()->resizeSection(2, 75);
|
||||||
|
horizontalHeader()->setSectionResizeMode(3, QHeaderView::Fixed);
|
||||||
|
horizontalHeader()->resizeSection(3, 75);
|
||||||
|
horizontalHeader()->setSectionResizeMode(4, QHeaderView::Fixed);
|
||||||
|
horizontalHeader()->resizeSection(4, 75);
|
||||||
|
horizontalHeader()->setSectionResizeMode(5, QHeaderView::Fixed);
|
||||||
|
horizontalHeader()->resizeSection(5, 75);
|
||||||
|
horizontalHeader()->setSectionResizeMode(6, QHeaderView::Fixed);
|
||||||
|
horizontalHeader()->resizeSection(6, 75);
|
||||||
|
horizontalHeader()->setSectionResizeMode(7, QHeaderView::Fixed);
|
||||||
|
horizontalHeader()->resizeSection(7, 75);
|
||||||
|
}
|
||||||
|
|
||||||
|
LayersTableView::LayersTableView(QWidget* parent)
|
||||||
|
: QTableView(parent)
|
||||||
|
{
|
||||||
|
setSelectionBehavior(QAbstractItemView::SelectRows);
|
||||||
|
setSelectionMode(QAbstractItemView::ExtendedSelection);
|
||||||
|
setDragDropMode(QAbstractItemView::InternalMove);
|
||||||
|
setDefaultDropAction(Qt::MoveAction);
|
||||||
|
setDragEnabled(true);
|
||||||
|
setGridStyle(Qt::NoPen);
|
||||||
|
|
||||||
|
m_signedDelegate.setItemEditorFactory(&m_signedFactory);
|
||||||
|
m_unsignedDelegate.setItemEditorFactory(&m_unsignedFactory);
|
||||||
|
|
||||||
|
setItemDelegateForColumn(0, &m_smDelegate);
|
||||||
|
setItemDelegateForColumn(1, &m_unsignedDelegate);
|
||||||
|
setItemDelegateForColumn(2, &m_unsignedDelegate);
|
||||||
|
setItemDelegateForColumn(3, &m_signedDelegate);
|
||||||
|
setItemDelegateForColumn(4, &m_unsignedDelegate);
|
||||||
|
setItemDelegateForColumn(5, &m_signedDelegate);
|
||||||
|
setItemDelegateForColumn(6, &m_unsignedDelegate);
|
||||||
|
setItemDelegateForColumn(7, &m_unsignedDelegate);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool LayersEditor::loadData(ProjectModel::LayersNode* node)
|
||||||
|
{
|
||||||
|
m_model.loadData(node);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void LayersEditor::unloadData()
|
||||||
|
{
|
||||||
|
m_model.unloadData();
|
||||||
|
}
|
||||||
|
|
||||||
|
ProjectModel::INode* LayersEditor::currentNode() const
|
||||||
|
{
|
||||||
|
return m_model.m_node.get();
|
||||||
|
}
|
||||||
|
|
||||||
|
void LayersEditor::resizeEvent(QResizeEvent* ev)
|
||||||
|
{
|
||||||
|
m_tableView.setGeometry(QRect({}, ev->size()));
|
||||||
|
m_addRemoveButtons.move(0, ev->size().height() - 32);
|
||||||
|
}
|
||||||
|
|
||||||
|
void LayersEditor::rowsInserted(const QModelIndex& parent, int first, int last)
|
||||||
|
{
|
||||||
|
m_tableView.scrollTo(m_tableView.model()->index(first, 0));
|
||||||
|
}
|
||||||
|
|
||||||
|
void LayersEditor::rowsMoved(const QModelIndex& parent, int start, int end, const QModelIndex& destination, int row)
|
||||||
|
{
|
||||||
|
m_tableView.scrollTo(m_tableView.model()->index(row, 0));
|
||||||
|
}
|
||||||
|
|
||||||
|
void LayersEditor::doAdd()
|
||||||
|
{
|
||||||
|
QModelIndex idx = m_tableView.selectionModel()->currentIndex();
|
||||||
|
std::vector<std::pair<amuse::LayerMapping, int>> data;
|
||||||
|
if (!idx.isValid())
|
||||||
|
data.push_back(std::make_pair(amuse::LayerMapping{}, m_model.rowCount() - 1));
|
||||||
|
else
|
||||||
|
data.push_back(std::make_pair(amuse::LayerMapping{}, idx.row()));
|
||||||
|
g_MainWindow->pushUndoCommand(new LayerRowAddUndoCommand(m_model.m_node.get(),
|
||||||
|
tr("Add Layer"), &m_tableView, std::move(data)));
|
||||||
|
}
|
||||||
|
|
||||||
|
void LayersEditor::doSelectionChanged()
|
||||||
|
{
|
||||||
|
m_addRemoveButtons.removeAction()->setDisabled(m_tableView.selectionModel()->selectedRows().isEmpty());
|
||||||
|
g_MainWindow->updateFocus();
|
||||||
|
}
|
||||||
|
|
||||||
|
AmuseItemEditFlags LayersEditor::itemEditFlags() const
|
||||||
|
{
|
||||||
|
return m_tableView.selectionModel()->selectedRows().isEmpty() ? AmuseItemNone : AmuseItemDelete;
|
||||||
|
}
|
||||||
|
|
||||||
|
void LayersEditor::itemDeleteAction()
|
||||||
|
{
|
||||||
|
m_tableView.deleteSelection();
|
||||||
|
}
|
||||||
|
|
||||||
|
LayersEditor::LayersEditor(QWidget* parent)
|
||||||
|
: EditorWidget(parent), m_model(this), m_tableView(this), m_addRemoveButtons(this)
|
||||||
|
{
|
||||||
|
m_tableView.setModel(&m_model);
|
||||||
|
connect(m_tableView.selectionModel(), SIGNAL(selectionChanged(const QItemSelection&, const QItemSelection&)),
|
||||||
|
this, SLOT(doSelectionChanged()));
|
||||||
|
connect(&m_model, SIGNAL(rowsInserted(const QModelIndex&, int, int)),
|
||||||
|
this, SLOT(rowsInserted(const QModelIndex&, int, int)));
|
||||||
|
connect(&m_model, SIGNAL(rowsMoved(const QModelIndex&, int, int, const QModelIndex&, int)),
|
||||||
|
this, SLOT(rowsMoved(const QModelIndex&, int, int, const QModelIndex&, int)));
|
||||||
|
|
||||||
|
m_addRemoveButtons.addAction()->setToolTip(tr("Add new layer mapping"));
|
||||||
|
connect(m_addRemoveButtons.addAction(), SIGNAL(triggered(bool)), this, SLOT(doAdd()));
|
||||||
|
m_addRemoveButtons.removeAction()->setToolTip(tr("Remove selected layer mappings"));
|
||||||
|
connect(m_addRemoveButtons.removeAction(), SIGNAL(triggered(bool)), this, SLOT(itemDeleteAction()));
|
||||||
|
}
|
||||||
92
Editor/LayersEditor.hpp
Normal file
@@ -0,0 +1,92 @@
|
|||||||
|
#ifndef AMUSE_LAYERS_EDITOR_HPP
|
||||||
|
#define AMUSE_LAYERS_EDITOR_HPP
|
||||||
|
|
||||||
|
#include "EditorWidget.hpp"
|
||||||
|
#include <QAbstractTableModel>
|
||||||
|
#include <QTableView>
|
||||||
|
#include <QAction>
|
||||||
|
#include <QToolButton>
|
||||||
|
#include <QStyledItemDelegate>
|
||||||
|
|
||||||
|
class SoundMacroDelegate : public BaseObjectDelegate
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
protected:
|
||||||
|
ProjectModel::INode* getNode(const QAbstractItemModel* model, const QModelIndex& index) const;
|
||||||
|
public:
|
||||||
|
explicit SoundMacroDelegate(QObject* parent = Q_NULLPTR);
|
||||||
|
QWidget* createEditor(QWidget* parent, const QStyleOptionViewItem& option, const QModelIndex& index) const;
|
||||||
|
void setEditorData(QWidget* editor, const QModelIndex& index) const;
|
||||||
|
void setModelData(QWidget* editor, QAbstractItemModel* model, const QModelIndex& index) const;
|
||||||
|
private slots:
|
||||||
|
void smIndexChanged();
|
||||||
|
};
|
||||||
|
|
||||||
|
class LayersModel : public QAbstractTableModel
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
friend class LayersEditor;
|
||||||
|
friend class SoundMacroDelegate;
|
||||||
|
friend class LayersTableView;
|
||||||
|
amuse::ObjToken<ProjectModel::LayersNode> m_node;
|
||||||
|
public:
|
||||||
|
explicit LayersModel(QObject* parent = Q_NULLPTR);
|
||||||
|
void loadData(ProjectModel::LayersNode* node);
|
||||||
|
void unloadData();
|
||||||
|
|
||||||
|
int rowCount(const QModelIndex& parent = QModelIndex()) const;
|
||||||
|
int columnCount(const QModelIndex& parent = QModelIndex()) const;
|
||||||
|
QVariant data(const QModelIndex& index, int role = Qt::DisplayRole) const;
|
||||||
|
bool setData(const QModelIndex& index, const QVariant& value, int role = Qt::EditRole);
|
||||||
|
QVariant headerData(int section, Qt::Orientation orientation, int role = Qt::DisplayRole) const;
|
||||||
|
Qt::ItemFlags flags(const QModelIndex& index) const;
|
||||||
|
Qt::DropActions supportedDropActions() const;
|
||||||
|
Qt::DropActions supportedDragActions() const;
|
||||||
|
bool dropMimeData(const QMimeData *data, Qt::DropAction action,
|
||||||
|
int row, int column, const QModelIndex &parent);
|
||||||
|
|
||||||
|
bool insertRows(int row, int count, const QModelIndex& parent = QModelIndex());
|
||||||
|
bool moveRows(const QModelIndex& sourceParent, int sourceRow, int count,
|
||||||
|
const QModelIndex& destinationParent, int destinationChild);
|
||||||
|
bool removeRows(int row, int count, const QModelIndex& parent = QModelIndex());
|
||||||
|
|
||||||
|
void _insertRow(int row, const amuse::LayerMapping& data);
|
||||||
|
amuse::LayerMapping _removeRow(int row);
|
||||||
|
};
|
||||||
|
|
||||||
|
class LayersTableView : public QTableView
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
SoundMacroDelegate m_smDelegate;
|
||||||
|
RangedValueFactory<-128, 127> m_signedFactory;
|
||||||
|
RangedValueFactory<0, 127> m_unsignedFactory;
|
||||||
|
QStyledItemDelegate m_signedDelegate, m_unsignedDelegate;
|
||||||
|
public:
|
||||||
|
explicit LayersTableView(QWidget* parent = Q_NULLPTR);
|
||||||
|
void setModel(QAbstractItemModel* model);
|
||||||
|
void deleteSelection();
|
||||||
|
};
|
||||||
|
|
||||||
|
class LayersEditor : public EditorWidget
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
friend class LayersModel;
|
||||||
|
LayersModel m_model;
|
||||||
|
LayersTableView m_tableView;
|
||||||
|
AddRemoveButtons m_addRemoveButtons;
|
||||||
|
public:
|
||||||
|
explicit LayersEditor(QWidget* parent = Q_NULLPTR);
|
||||||
|
bool loadData(ProjectModel::LayersNode* node);
|
||||||
|
void unloadData();
|
||||||
|
ProjectModel::INode* currentNode() const;
|
||||||
|
void resizeEvent(QResizeEvent* ev);
|
||||||
|
AmuseItemEditFlags itemEditFlags() const;
|
||||||
|
private slots:
|
||||||
|
void rowsInserted(const QModelIndex& parent, int first, int last);
|
||||||
|
void rowsMoved(const QModelIndex& parent, int start, int end, const QModelIndex& destination, int row);
|
||||||
|
void doAdd();
|
||||||
|
void doSelectionChanged();
|
||||||
|
void itemDeleteAction();
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif //AMUSE_LAYERS_EDITOR_HPP
|
||||||
169
Editor/MIDIReader.cpp
Normal file
@@ -0,0 +1,169 @@
|
|||||||
|
#include "MIDIReader.hpp"
|
||||||
|
#include "MainWindow.hpp"
|
||||||
|
|
||||||
|
MIDIReader::MIDIReader(amuse::Engine& engine, bool useLock)
|
||||||
|
: amuse::BooBackendMIDIReader(engine, useLock) {}
|
||||||
|
|
||||||
|
void MIDIReader::noteOff(uint8_t chan, uint8_t key, uint8_t velocity)
|
||||||
|
{
|
||||||
|
if (g_MainWindow->m_interactiveSeq)
|
||||||
|
{
|
||||||
|
g_MainWindow->m_interactiveSeq->keyOff(chan, key, velocity);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto keySearch = m_chanVoxs.find(key);
|
||||||
|
if (keySearch == m_chanVoxs.cend())
|
||||||
|
return;
|
||||||
|
|
||||||
|
if ((m_lastVoice && m_lastVoice->isDestroyed()) || keySearch->second == m_lastVoice)
|
||||||
|
m_lastVoice.reset();
|
||||||
|
keySearch->second->keyOff();
|
||||||
|
m_keyoffVoxs.emplace(std::move(keySearch->second));
|
||||||
|
m_chanVoxs.erase(keySearch);
|
||||||
|
}
|
||||||
|
|
||||||
|
void MIDIReader::noteOn(uint8_t chan, uint8_t key, uint8_t velocity)
|
||||||
|
{
|
||||||
|
if (g_MainWindow->m_interactiveSeq)
|
||||||
|
{
|
||||||
|
g_MainWindow->m_interactiveSeq->keyOn(chan, key, velocity);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (m_lastVoice && m_lastVoice->isDestroyed())
|
||||||
|
m_lastVoice.reset();
|
||||||
|
|
||||||
|
/* If portamento is enabled for voice, pre-empt spawning new voices */
|
||||||
|
if (amuse::ObjToken<amuse::Voice> lastVoice = m_lastVoice)
|
||||||
|
{
|
||||||
|
uint8_t lastNote = lastVoice->getLastNote();
|
||||||
|
if (lastVoice->doPortamento(key))
|
||||||
|
{
|
||||||
|
m_chanVoxs.erase(lastNote);
|
||||||
|
m_chanVoxs[key] = lastVoice;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Ensure keyoff sent first */
|
||||||
|
auto keySearch = m_chanVoxs.find(key);
|
||||||
|
if (keySearch != m_chanVoxs.cend())
|
||||||
|
{
|
||||||
|
if (keySearch->second == m_lastVoice)
|
||||||
|
m_lastVoice.reset();
|
||||||
|
keySearch->second->keyOff();
|
||||||
|
keySearch->second->setPedal(false);
|
||||||
|
m_keyoffVoxs.emplace(std::move(keySearch->second));
|
||||||
|
m_chanVoxs.erase(keySearch);
|
||||||
|
}
|
||||||
|
|
||||||
|
amuse::ObjToken<amuse::Voice> newVox = g_MainWindow->startEditorVoice(key, velocity);
|
||||||
|
if (newVox)
|
||||||
|
{
|
||||||
|
m_chanVoxs[key] = newVox;
|
||||||
|
m_lastVoice = newVox;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void MIDIReader::notePressure(uint8_t /*chan*/, uint8_t /*key*/, uint8_t /*pressure*/) {}
|
||||||
|
|
||||||
|
void MIDIReader::controlChange(uint8_t chan, uint8_t control, uint8_t value)
|
||||||
|
{
|
||||||
|
if (g_MainWindow->m_interactiveSeq)
|
||||||
|
{
|
||||||
|
g_MainWindow->m_interactiveSeq->setCtrlValue(chan, control, value);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (control == 1)
|
||||||
|
{
|
||||||
|
g_MainWindow->m_ui.modulationSlider->setValue(int(value));
|
||||||
|
}
|
||||||
|
else if (control == 64)
|
||||||
|
{
|
||||||
|
g_MainWindow->setSustain(value >= 0x40);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
for (auto& v : m_engine.getActiveVoices())
|
||||||
|
v->setCtrlValue(control, value);
|
||||||
|
}
|
||||||
|
g_MainWindow->m_ctrlVals[control] = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
void MIDIReader::programChange(uint8_t chan, uint8_t program)
|
||||||
|
{
|
||||||
|
if (g_MainWindow->m_interactiveSeq)
|
||||||
|
g_MainWindow->m_interactiveSeq->setChanProgram(chan, program);
|
||||||
|
}
|
||||||
|
|
||||||
|
void MIDIReader::channelPressure(uint8_t /*chan*/, uint8_t /*pressure*/) {}
|
||||||
|
|
||||||
|
void MIDIReader::pitchBend(uint8_t chan, int16_t pitch)
|
||||||
|
{
|
||||||
|
float pWheel = (pitch - 0x2000) / float(0x2000);
|
||||||
|
if (g_MainWindow->m_interactiveSeq)
|
||||||
|
g_MainWindow->m_interactiveSeq->setPitchWheel(chan, pWheel);
|
||||||
|
else
|
||||||
|
g_MainWindow->m_ui.pitchSlider->setValue(int(pWheel * 2048.f));
|
||||||
|
}
|
||||||
|
|
||||||
|
void MIDIReader::allSoundOff(uint8_t chan)
|
||||||
|
{
|
||||||
|
if (g_MainWindow->m_interactiveSeq)
|
||||||
|
{
|
||||||
|
g_MainWindow->m_interactiveSeq->kill();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (auto& v : m_engine.getActiveVoices())
|
||||||
|
v->kill();
|
||||||
|
}
|
||||||
|
|
||||||
|
void MIDIReader::resetAllControllers(uint8_t /*chan*/) {}
|
||||||
|
|
||||||
|
void MIDIReader::localControl(uint8_t /*chan*/, bool /*on*/) {}
|
||||||
|
|
||||||
|
void MIDIReader::allNotesOff(uint8_t chan)
|
||||||
|
{
|
||||||
|
if (g_MainWindow->m_interactiveSeq)
|
||||||
|
{
|
||||||
|
g_MainWindow->m_interactiveSeq->kill();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (auto& v : m_engine.getActiveVoices())
|
||||||
|
v->kill();
|
||||||
|
}
|
||||||
|
|
||||||
|
void MIDIReader::omniMode(uint8_t /*chan*/, bool /*on*/) {}
|
||||||
|
|
||||||
|
void MIDIReader::polyMode(uint8_t /*chan*/, bool /*on*/) {}
|
||||||
|
|
||||||
|
void MIDIReader::sysex(const void* /*data*/, size_t /*len*/) {}
|
||||||
|
|
||||||
|
void MIDIReader::timeCodeQuarterFrame(uint8_t /*message*/, uint8_t /*value*/) {}
|
||||||
|
|
||||||
|
void MIDIReader::songPositionPointer(uint16_t /*pointer*/) {}
|
||||||
|
|
||||||
|
void MIDIReader::songSelect(uint8_t /*song*/) {}
|
||||||
|
|
||||||
|
void MIDIReader::tuneRequest() {}
|
||||||
|
|
||||||
|
void MIDIReader::startSeq() {}
|
||||||
|
|
||||||
|
void MIDIReader::continueSeq() {}
|
||||||
|
|
||||||
|
void MIDIReader::stopSeq() {}
|
||||||
|
|
||||||
|
void MIDIReader::reset() {}
|
||||||
|
|
||||||
|
VoiceAllocator::VoiceAllocator(boo::IAudioVoiceEngine& booEngine)
|
||||||
|
: amuse::BooBackendVoiceAllocator(booEngine) {}
|
||||||
|
|
||||||
|
std::unique_ptr<amuse::IMIDIReader>
|
||||||
|
VoiceAllocator::allocateMIDIReader(amuse::Engine& engine)
|
||||||
|
{
|
||||||
|
return std::make_unique<MIDIReader>(engine, m_booEngine.useMIDILock());
|
||||||
|
}
|
||||||
52
Editor/MIDIReader.hpp
Normal file
@@ -0,0 +1,52 @@
|
|||||||
|
#ifndef AMUSE_MIDI_READER_HPP
|
||||||
|
#define AMUSE_MIDI_READER_HPP
|
||||||
|
|
||||||
|
#include "amuse/Voice.hpp"
|
||||||
|
#include "amuse/BooBackend.hpp"
|
||||||
|
#include "amuse/Common.hpp"
|
||||||
|
#include <unordered_set>
|
||||||
|
|
||||||
|
class MIDIReader : public amuse::BooBackendMIDIReader
|
||||||
|
{
|
||||||
|
std::unordered_map<uint8_t, amuse::ObjToken<amuse::Voice>> m_chanVoxs;
|
||||||
|
std::unordered_set<amuse::ObjToken<amuse::Voice>> m_keyoffVoxs;
|
||||||
|
amuse::ObjToken<amuse::Voice> m_lastVoice;
|
||||||
|
public:
|
||||||
|
MIDIReader(amuse::Engine& engine, bool useLock);
|
||||||
|
|
||||||
|
void noteOff(uint8_t chan, uint8_t key, uint8_t velocity);
|
||||||
|
void noteOn(uint8_t chan, uint8_t key, uint8_t velocity);
|
||||||
|
void notePressure(uint8_t chan, uint8_t key, uint8_t pressure);
|
||||||
|
void controlChange(uint8_t chan, uint8_t control, uint8_t value);
|
||||||
|
void programChange(uint8_t chan, uint8_t program);
|
||||||
|
void channelPressure(uint8_t chan, uint8_t pressure);
|
||||||
|
void pitchBend(uint8_t chan, int16_t pitch);
|
||||||
|
|
||||||
|
void allSoundOff(uint8_t chan);
|
||||||
|
void resetAllControllers(uint8_t chan);
|
||||||
|
void localControl(uint8_t chan, bool on);
|
||||||
|
void allNotesOff(uint8_t chan);
|
||||||
|
void omniMode(uint8_t chan, bool on);
|
||||||
|
void polyMode(uint8_t chan, bool on);
|
||||||
|
|
||||||
|
void sysex(const void* data, size_t len);
|
||||||
|
void timeCodeQuarterFrame(uint8_t message, uint8_t value);
|
||||||
|
void songPositionPointer(uint16_t pointer);
|
||||||
|
void songSelect(uint8_t song);
|
||||||
|
void tuneRequest();
|
||||||
|
|
||||||
|
void startSeq();
|
||||||
|
void continueSeq();
|
||||||
|
void stopSeq();
|
||||||
|
|
||||||
|
void reset();
|
||||||
|
};
|
||||||
|
|
||||||
|
class VoiceAllocator : public amuse::BooBackendVoiceAllocator
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
VoiceAllocator(boo::IAudioVoiceEngine& booEngine);
|
||||||
|
std::unique_ptr<amuse::IMIDIReader> allocateMIDIReader(amuse::Engine& engine);
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // AMUSE_MIDI_READER_HPP
|
||||||
9
Editor/MacOSExtras.mm
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
#import <AppKit/AppKit.h>
|
||||||
|
|
||||||
|
void MacOSSetDarkAppearance()
|
||||||
|
{
|
||||||
|
#if __MAC_OS_X_VERSION_MAX_ALLOWED >= 101400
|
||||||
|
if ([NSApp respondsToSelector:@selector(setAppearance:)])
|
||||||
|
[NSApp setAppearance:[NSAppearance appearanceNamed:NSAppearanceNameDarkAqua]];
|
||||||
|
#endif
|
||||||
|
}
|
||||||
2115
Editor/MainWindow.cpp
Normal file
309
Editor/MainWindow.hpp
Normal file
@@ -0,0 +1,309 @@
|
|||||||
|
#ifndef AMUSE_MAINWINDOW_HPP
|
||||||
|
#define AMUSE_MAINWINDOW_HPP
|
||||||
|
|
||||||
|
#include <QMainWindow>
|
||||||
|
#include <QUndoStack>
|
||||||
|
#include <QProgressDialog>
|
||||||
|
#include <QThread>
|
||||||
|
#include <QStyledItemDelegate>
|
||||||
|
#include <QSortFilterProxyModel>
|
||||||
|
#include <QLinkedList>
|
||||||
|
#include <QFileDialog>
|
||||||
|
#include "ui_MainWindow.h"
|
||||||
|
#include "amuse/Engine.hpp"
|
||||||
|
#include "amuse/BooBackend.hpp"
|
||||||
|
#include "boo/audiodev/IAudioVoiceEngine.hpp"
|
||||||
|
#include "ProjectModel.hpp"
|
||||||
|
#include "EditorWidget.hpp"
|
||||||
|
#include "MIDIReader.hpp"
|
||||||
|
#include "StudioSetupWidget.hpp"
|
||||||
|
|
||||||
|
#define MaxRecentFiles 4
|
||||||
|
|
||||||
|
namespace Ui {
|
||||||
|
class MainWindow;
|
||||||
|
}
|
||||||
|
|
||||||
|
class MainWindow;
|
||||||
|
class SongGroupEditor;
|
||||||
|
class SoundGroupEditor;
|
||||||
|
class SoundMacroEditor;
|
||||||
|
class ADSREditor;
|
||||||
|
class CurveEditor;
|
||||||
|
class KeymapEditor;
|
||||||
|
class LayersEditor;
|
||||||
|
class SampleEditor;
|
||||||
|
|
||||||
|
enum BackgroundTaskId
|
||||||
|
{
|
||||||
|
TaskOpen,
|
||||||
|
TaskImport,
|
||||||
|
TaskExport,
|
||||||
|
TaskReloadSamples
|
||||||
|
};
|
||||||
|
|
||||||
|
class BackgroundTask : public QObject
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
int m_id;
|
||||||
|
std::function<void(BackgroundTask&)> m_task;
|
||||||
|
UIMessenger m_threadMessenger;
|
||||||
|
bool m_cancelled = false;
|
||||||
|
public:
|
||||||
|
explicit BackgroundTask(int id, std::function<void(BackgroundTask&)>&& task)
|
||||||
|
: m_id(id), m_task(std::move(task)), m_threadMessenger(this) {}
|
||||||
|
bool isCanceled() const { QCoreApplication::processEvents(); return m_cancelled; }
|
||||||
|
UIMessenger& uiMessenger() { return m_threadMessenger; }
|
||||||
|
|
||||||
|
signals:
|
||||||
|
void setMinimum(int minimum);
|
||||||
|
void setMaximum(int maximum);
|
||||||
|
void setValue(int value);
|
||||||
|
void setLabelText(const QString& text);
|
||||||
|
void finished(int id);
|
||||||
|
|
||||||
|
public slots:
|
||||||
|
void run() { m_task(*this); emit finished(m_id); }
|
||||||
|
void cancel() { m_cancelled = true; }
|
||||||
|
};
|
||||||
|
|
||||||
|
class TreeDelegate : public QStyledItemDelegate
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
MainWindow& m_window;
|
||||||
|
public:
|
||||||
|
explicit TreeDelegate(MainWindow& window, QObject* parent = Q_NULLPTR)
|
||||||
|
: QStyledItemDelegate(parent), m_window(window) {}
|
||||||
|
|
||||||
|
bool editorEvent(QEvent *event,
|
||||||
|
QAbstractItemModel *model,
|
||||||
|
const QStyleOptionViewItem &option,
|
||||||
|
const QModelIndex &index);
|
||||||
|
public slots:
|
||||||
|
void doExportGroup();
|
||||||
|
void doFindUsages();
|
||||||
|
void doCut();
|
||||||
|
void doCopy();
|
||||||
|
void doPaste();
|
||||||
|
void doDuplicate();
|
||||||
|
void doDelete();
|
||||||
|
void doRename();
|
||||||
|
};
|
||||||
|
|
||||||
|
class MainWindow : public QMainWindow
|
||||||
|
{
|
||||||
|
friend class MIDIReader;
|
||||||
|
friend class ProjectModel;
|
||||||
|
friend class GroupNodeUndoCommand;
|
||||||
|
friend class TreeDelegate;
|
||||||
|
Q_OBJECT
|
||||||
|
Ui::MainWindow m_ui;
|
||||||
|
QAction* m_goBack;
|
||||||
|
QAction* m_goForward;
|
||||||
|
QLinkedList<ProjectModel::INode*> m_navList;
|
||||||
|
QLinkedList<ProjectModel::INode*>::iterator m_navIt;
|
||||||
|
QAction* m_clearRecentFileAct;
|
||||||
|
QAction* m_recentFileActs[MaxRecentFiles];
|
||||||
|
TreeDelegate m_treeDelegate;
|
||||||
|
UIMessenger m_mainMessenger;
|
||||||
|
ProjectModel* m_projectModel = nullptr;
|
||||||
|
QWidget* m_faceSvg;
|
||||||
|
SongGroupEditor* m_songGroupEditor = nullptr;
|
||||||
|
SoundGroupEditor* m_soundGroupEditor = nullptr;
|
||||||
|
SoundMacroEditor* m_soundMacroEditor = nullptr;
|
||||||
|
ADSREditor* m_adsrEditor = nullptr;
|
||||||
|
CurveEditor* m_curveEditor = nullptr;
|
||||||
|
KeymapEditor* m_keymapEditor = nullptr;
|
||||||
|
LayersEditor* m_layersEditor = nullptr;
|
||||||
|
SampleEditor* m_sampleEditor = nullptr;
|
||||||
|
StudioSetupWidget* m_studioSetup = nullptr;
|
||||||
|
QFileDialog m_openDirectoryDialog;
|
||||||
|
QFileDialog m_openFileDialog;
|
||||||
|
QFileDialog m_newFileDialog;
|
||||||
|
|
||||||
|
std::unique_ptr<boo::IAudioVoiceEngine> m_voxEngine;
|
||||||
|
std::unique_ptr<VoiceAllocator> m_voxAllocator;
|
||||||
|
std::unique_ptr<amuse::Engine> m_engine;
|
||||||
|
amuse::ObjToken<amuse::Voice> m_lastSound;
|
||||||
|
amuse::ObjToken<amuse::Sequencer> m_interactiveSeq;
|
||||||
|
int m_velocity = 90;
|
||||||
|
float m_pitch = 0.f;
|
||||||
|
int8_t m_ctrlVals[128] = {};
|
||||||
|
float m_auxAVol = 0.f;
|
||||||
|
float m_auxBVol = 0.f;
|
||||||
|
bool m_uiDisabled = false;
|
||||||
|
bool m_clipboardAmuseData = false;
|
||||||
|
|
||||||
|
QUndoStack* m_undoStack;
|
||||||
|
|
||||||
|
QMetaObject::Connection m_cutConn;
|
||||||
|
QMetaObject::Connection m_copyConn;
|
||||||
|
QMetaObject::Connection m_pasteConn;
|
||||||
|
QMetaObject::Connection m_deleteConn;
|
||||||
|
QMetaObject::Connection m_canEditConn;
|
||||||
|
|
||||||
|
BackgroundTask* m_backgroundTask = nullptr;
|
||||||
|
QProgressDialog* m_backgroundDialog = nullptr;
|
||||||
|
QThread m_backgroundThread;
|
||||||
|
|
||||||
|
uint64_t m_timerFireCount = 0;
|
||||||
|
int m_peakVoices = 0;
|
||||||
|
|
||||||
|
void connectMessenger(UIMessenger* messenger, Qt::ConnectionType type);
|
||||||
|
|
||||||
|
void updateWindowTitle();
|
||||||
|
void updateRecentFileActions();
|
||||||
|
void updateNavigationButtons();
|
||||||
|
bool setProjectPath(const QString& path);
|
||||||
|
void refreshAudioIO();
|
||||||
|
void refreshMIDIIO();
|
||||||
|
void timerEvent(QTimerEvent* ev);
|
||||||
|
void setSustain(bool sustain);
|
||||||
|
void keyPressEvent(QKeyEvent* ev);
|
||||||
|
void keyReleaseEvent(QKeyEvent* ev);
|
||||||
|
|
||||||
|
void startBackgroundTask(int id, const QString& windowTitle, const QString& label,
|
||||||
|
std::function<void(BackgroundTask&)>&& task);
|
||||||
|
|
||||||
|
bool _setEditor(EditorWidget* widget, bool appendNav = true);
|
||||||
|
|
||||||
|
public:
|
||||||
|
explicit MainWindow(QWidget* parent = Q_NULLPTR);
|
||||||
|
~MainWindow();
|
||||||
|
|
||||||
|
bool openProject(const QString& path);
|
||||||
|
|
||||||
|
bool openEditor(ProjectModel::SongGroupNode* node, bool appendNav = true);
|
||||||
|
bool openEditor(ProjectModel::SoundGroupNode* node, bool appendNav = true);
|
||||||
|
bool openEditor(ProjectModel::SoundMacroNode* node, bool appendNav = true);
|
||||||
|
bool openEditor(ProjectModel::ADSRNode* node, bool appendNav = true);
|
||||||
|
bool openEditor(ProjectModel::CurveNode* node, bool appendNav = true);
|
||||||
|
bool openEditor(ProjectModel::KeymapNode* node, bool appendNav = true);
|
||||||
|
bool openEditor(ProjectModel::LayersNode* node, bool appendNav = true);
|
||||||
|
bool openEditor(ProjectModel::SampleNode* node, bool appendNav = true);
|
||||||
|
bool openEditor(ProjectModel::INode* node, bool appendNav = true);
|
||||||
|
void closeEditor();
|
||||||
|
|
||||||
|
ProjectModel::INode* getEditorNode() const;
|
||||||
|
EditorWidget* getEditorWidget() const;
|
||||||
|
amuse::ObjToken<amuse::Voice> startEditorVoice(uint8_t key, uint8_t vel);
|
||||||
|
amuse::ObjToken<amuse::Voice> startSFX(amuse::GroupId groupId, amuse::SFXId sfxId);
|
||||||
|
amuse::ObjToken<amuse::Sequencer> startSong(amuse::GroupId groupId, amuse::SongId songId,
|
||||||
|
const unsigned char* arrData);
|
||||||
|
void pushUndoCommand(EditorUndoCommand* cmd);
|
||||||
|
void updateFocus();
|
||||||
|
void aboutToDeleteNode(ProjectModel::INode* node);
|
||||||
|
bool askAboutSave();
|
||||||
|
void closeEvent(QCloseEvent* ev);
|
||||||
|
void showEvent(QShowEvent* ev);
|
||||||
|
|
||||||
|
QString getGroupName(ProjectModel::GroupNode* group) const;
|
||||||
|
ProjectModel::GroupNode* getSelectedGroupNode() const;
|
||||||
|
QString getSelectedGroupName() const;
|
||||||
|
void _recursiveExpandOutline(const QModelIndex& filterIndex) const;
|
||||||
|
void recursiveExpandAndSelectOutline(const QModelIndex& index) const;
|
||||||
|
|
||||||
|
ProjectModel* projectModel() const { return m_projectModel; }
|
||||||
|
UIMessenger& uiMessenger() { return m_mainMessenger; }
|
||||||
|
|
||||||
|
void setItemEditFlags(AmuseItemEditFlags flags);
|
||||||
|
void setItemNewEnabled(bool enabled);
|
||||||
|
AmuseItemEditFlags outlineEditFlags();
|
||||||
|
bool isUiDisabled() const { return m_uiDisabled; }
|
||||||
|
void findUsages(ProjectModel::INode* node);
|
||||||
|
|
||||||
|
public slots:
|
||||||
|
void newAction();
|
||||||
|
void _newAction(const QString& path);
|
||||||
|
void openAction();
|
||||||
|
void _openAction(const QString& path);
|
||||||
|
void openRecentFileAction();
|
||||||
|
void clearRecentFilesAction();
|
||||||
|
void saveAction();
|
||||||
|
void revertAction();
|
||||||
|
void reloadSampleDataAction();
|
||||||
|
void importAction();
|
||||||
|
void _importAction(const QString& path);
|
||||||
|
void importSongsAction();
|
||||||
|
void _importSongsAction(const QString& path);
|
||||||
|
void exportAction();
|
||||||
|
void importHeadersAction();
|
||||||
|
void _importHeadersAction(const QString& path);
|
||||||
|
void exportHeadersAction();
|
||||||
|
void _exportHeadersAction(const QString& path);
|
||||||
|
|
||||||
|
void newSubprojectAction();
|
||||||
|
void newSFXGroupAction();
|
||||||
|
void newSongGroupAction();
|
||||||
|
void newSoundMacroAction();
|
||||||
|
void newADSRAction();
|
||||||
|
void newCurveAction();
|
||||||
|
void newKeymapAction();
|
||||||
|
void newLayersAction();
|
||||||
|
|
||||||
|
void goForward();
|
||||||
|
void goBack();
|
||||||
|
|
||||||
|
void aboutToShowAudioIOMenu();
|
||||||
|
void aboutToShowMIDIIOMenu();
|
||||||
|
|
||||||
|
void setAudioIO();
|
||||||
|
void setMIDIIO(bool checked);
|
||||||
|
|
||||||
|
void aboutAmuseAction();
|
||||||
|
void aboutQtAction();
|
||||||
|
|
||||||
|
void notePressed(int key);
|
||||||
|
void noteReleased();
|
||||||
|
void velocityChanged(int vel);
|
||||||
|
void modulationChanged(int mod);
|
||||||
|
void pitchChanged(int pitch);
|
||||||
|
void killSounds();
|
||||||
|
void fxPressed();
|
||||||
|
void volumeChanged(int vol);
|
||||||
|
void auxAChanged(int vol);
|
||||||
|
void auxBChanged(int vol);
|
||||||
|
|
||||||
|
void outlineCutAction();
|
||||||
|
void outlineCopyAction();
|
||||||
|
void outlinePasteAction();
|
||||||
|
void outlineDeleteAction();
|
||||||
|
|
||||||
|
void onFocusChanged(QWidget* old, QWidget* now);
|
||||||
|
void onClipboardChanged();
|
||||||
|
void outlineItemActivated(const QModelIndex& index);
|
||||||
|
void onOutlineSelectionChanged(const QItemSelection& selected, const QItemSelection& deselected);
|
||||||
|
void onTextSelect();
|
||||||
|
void onTextDelete();
|
||||||
|
void cleanChanged(bool clean);
|
||||||
|
|
||||||
|
void studioSetupHidden();
|
||||||
|
void studioSetupShown();
|
||||||
|
|
||||||
|
void onBackgroundTaskFinished(int id);
|
||||||
|
|
||||||
|
QMessageBox::StandardButton msgInformation(const QString &title,
|
||||||
|
const QString &text, QMessageBox::StandardButtons buttons = QMessageBox::Ok,
|
||||||
|
QMessageBox::StandardButton defaultButton = QMessageBox::NoButton);
|
||||||
|
int msgQuestion(const QString &title,
|
||||||
|
const QString& text,
|
||||||
|
const QString& button0Text,
|
||||||
|
const QString& button1Text = QString(),
|
||||||
|
const QString& button2Text = QString(),
|
||||||
|
int defaultButtonNumber = 0,
|
||||||
|
int escapeButtonNumber = -1);
|
||||||
|
QMessageBox::StandardButton msgQuestion(const QString &title,
|
||||||
|
const QString &text, QMessageBox::StandardButtons buttons =
|
||||||
|
QMessageBox::StandardButtons(QMessageBox::Yes | QMessageBox::No),
|
||||||
|
QMessageBox::StandardButton defaultButton = QMessageBox::NoButton);
|
||||||
|
QMessageBox::StandardButton msgWarning(const QString &title,
|
||||||
|
const QString &text, QMessageBox::StandardButtons buttons = QMessageBox::Ok,
|
||||||
|
QMessageBox::StandardButton defaultButton = QMessageBox::NoButton);
|
||||||
|
QMessageBox::StandardButton msgCritical(const QString &title,
|
||||||
|
const QString &text, QMessageBox::StandardButtons buttons = QMessageBox::Ok,
|
||||||
|
QMessageBox::StandardButton defaultButton = QMessageBox::NoButton);
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
#endif //AMUSE_MAINWINDOW_HPP
|
||||||
730
Editor/MainWindow.ui
Normal file
@@ -0,0 +1,730 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<ui version="4.0">
|
||||||
|
<class>MainWindow</class>
|
||||||
|
<widget class="QMainWindow" name="MainWindow">
|
||||||
|
<property name="geometry">
|
||||||
|
<rect>
|
||||||
|
<x>0</x>
|
||||||
|
<y>0</y>
|
||||||
|
<width>1360</width>
|
||||||
|
<height>768</height>
|
||||||
|
</rect>
|
||||||
|
</property>
|
||||||
|
<property name="windowTitle">
|
||||||
|
<string>Amuse</string>
|
||||||
|
</property>
|
||||||
|
<widget class="QWidget" name="centralwidget">
|
||||||
|
<layout class="QGridLayout" name="gridLayout">
|
||||||
|
<property name="leftMargin">
|
||||||
|
<number>0</number>
|
||||||
|
</property>
|
||||||
|
<property name="topMargin">
|
||||||
|
<number>0</number>
|
||||||
|
</property>
|
||||||
|
<property name="rightMargin">
|
||||||
|
<number>0</number>
|
||||||
|
</property>
|
||||||
|
<property name="bottomMargin">
|
||||||
|
<number>0</number>
|
||||||
|
</property>
|
||||||
|
<property name="spacing">
|
||||||
|
<number>0</number>
|
||||||
|
</property>
|
||||||
|
<item row="0" column="0">
|
||||||
|
<widget class="QSplitter" name="splitter">
|
||||||
|
<property name="sizePolicy">
|
||||||
|
<sizepolicy hsizetype="MinimumExpanding" vsizetype="Preferred">
|
||||||
|
<horstretch>0</horstretch>
|
||||||
|
<verstretch>0</verstretch>
|
||||||
|
</sizepolicy>
|
||||||
|
</property>
|
||||||
|
<property name="minimumSize">
|
||||||
|
<size>
|
||||||
|
<width>950</width>
|
||||||
|
<height>0</height>
|
||||||
|
</size>
|
||||||
|
</property>
|
||||||
|
<property name="orientation">
|
||||||
|
<enum>Qt::Horizontal</enum>
|
||||||
|
</property>
|
||||||
|
<widget class="QWidget" name="projectOutlineContainer">
|
||||||
|
<layout class="QVBoxLayout" name="outlineLayout">
|
||||||
|
<property name="spacing">
|
||||||
|
<number>0</number>
|
||||||
|
</property>
|
||||||
|
<item>
|
||||||
|
<layout class="QHBoxLayout" name="outlineLayout2">
|
||||||
|
<property name="spacing">
|
||||||
|
<number>0</number>
|
||||||
|
</property>
|
||||||
|
<item>
|
||||||
|
<widget class="QLineEdit" name="projectOutlineFilter">
|
||||||
|
<property name="sizePolicy">
|
||||||
|
<sizepolicy hsizetype="Preferred" vsizetype="Preferred">
|
||||||
|
<horstretch>0</horstretch>
|
||||||
|
<verstretch>0</verstretch>
|
||||||
|
</sizepolicy>
|
||||||
|
</property>
|
||||||
|
<property name="minimumSize">
|
||||||
|
<size>
|
||||||
|
<width>200</width>
|
||||||
|
<height>0</height>
|
||||||
|
</size>
|
||||||
|
</property>
|
||||||
|
<property name="placeholderText">
|
||||||
|
<string>Filter</string>
|
||||||
|
</property>
|
||||||
|
<property name="clearButtonEnabled">
|
||||||
|
<bool>true</bool>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QToolButton" name="backButton">
|
||||||
|
<property name="enabled">
|
||||||
|
<bool>false</bool>
|
||||||
|
</property>
|
||||||
|
<property name="icon">
|
||||||
|
<iconset resource="resources/resources.qrc">
|
||||||
|
<normaloff>:/icons/IconBack.svg</normaloff>
|
||||||
|
<disabledoff>:/icons/IconBackDisabled.svg</disabledoff>
|
||||||
|
<disabledon>:/icons/IconBackDisabled.svg</disabledon>:/icons/IconBack.svg</iconset>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QToolButton" name="forwardButton">
|
||||||
|
<property name="enabled">
|
||||||
|
<bool>false</bool>
|
||||||
|
</property>
|
||||||
|
<property name="icon">
|
||||||
|
<iconset resource="resources/resources.qrc">
|
||||||
|
<normaloff>:/icons/IconForward.svg</normaloff>
|
||||||
|
<disabledoff>:/icons/IconForwardDisabled.svg</disabledoff>
|
||||||
|
<disabledon>:/icons/IconForwardDisabled.svg</disabledon>:/icons/IconForward.svg</iconset>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QTreeView" name="projectOutline">
|
||||||
|
<property name="sizePolicy">
|
||||||
|
<sizepolicy hsizetype="Preferred" vsizetype="Preferred">
|
||||||
|
<horstretch>0</horstretch>
|
||||||
|
<verstretch>1</verstretch>
|
||||||
|
</sizepolicy>
|
||||||
|
</property>
|
||||||
|
<property name="minimumSize">
|
||||||
|
<size>
|
||||||
|
<width>200</width>
|
||||||
|
<height>0</height>
|
||||||
|
</size>
|
||||||
|
</property>
|
||||||
|
<property name="focusPolicy">
|
||||||
|
<enum>Qt::WheelFocus</enum>
|
||||||
|
</property>
|
||||||
|
<property name="editTriggers">
|
||||||
|
<set>QAbstractItemView::EditKeyPressed|QAbstractItemView::SelectedClicked</set>
|
||||||
|
</property>
|
||||||
|
<property name="animated">
|
||||||
|
<bool>true</bool>
|
||||||
|
</property>
|
||||||
|
<attribute name="headerVisible">
|
||||||
|
<bool>false</bool>
|
||||||
|
</attribute>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</widget>
|
||||||
|
<widget class="QSplitter" name="rightSplitter">
|
||||||
|
<property name="sizePolicy">
|
||||||
|
<sizepolicy hsizetype="Expanding" vsizetype="Expanding">
|
||||||
|
<horstretch>1</horstretch>
|
||||||
|
<verstretch>0</verstretch>
|
||||||
|
</sizepolicy>
|
||||||
|
</property>
|
||||||
|
<property name="orientation">
|
||||||
|
<enum>Qt::Vertical</enum>
|
||||||
|
</property>
|
||||||
|
<widget class="QStackedWidget" name="editorContents"/>
|
||||||
|
<widget class="QWidget" name="keyboard" native="true">
|
||||||
|
<property name="sizePolicy">
|
||||||
|
<sizepolicy hsizetype="Preferred" vsizetype="Fixed">
|
||||||
|
<horstretch>0</horstretch>
|
||||||
|
<verstretch>0</verstretch>
|
||||||
|
</sizepolicy>
|
||||||
|
</property>
|
||||||
|
<property name="minimumSize">
|
||||||
|
<size>
|
||||||
|
<width>0</width>
|
||||||
|
<height>100</height>
|
||||||
|
</size>
|
||||||
|
</property>
|
||||||
|
<property name="maximumSize">
|
||||||
|
<size>
|
||||||
|
<width>16777215</width>
|
||||||
|
<height>100</height>
|
||||||
|
</size>
|
||||||
|
</property>
|
||||||
|
<layout class="QHBoxLayout" name="horizontalLayout">
|
||||||
|
<property name="spacing">
|
||||||
|
<number>6</number>
|
||||||
|
</property>
|
||||||
|
<property name="leftMargin">
|
||||||
|
<number>0</number>
|
||||||
|
</property>
|
||||||
|
<property name="topMargin">
|
||||||
|
<number>0</number>
|
||||||
|
</property>
|
||||||
|
<property name="rightMargin">
|
||||||
|
<number>6</number>
|
||||||
|
</property>
|
||||||
|
<property name="bottomMargin">
|
||||||
|
<number>0</number>
|
||||||
|
</property>
|
||||||
|
<item>
|
||||||
|
<widget class="PitchSlider" name="pitchSlider">
|
||||||
|
<property name="sizePolicy">
|
||||||
|
<sizepolicy hsizetype="Fixed" vsizetype="Fixed">
|
||||||
|
<horstretch>0</horstretch>
|
||||||
|
<verstretch>0</verstretch>
|
||||||
|
</sizepolicy>
|
||||||
|
</property>
|
||||||
|
<property name="minimumSize">
|
||||||
|
<size>
|
||||||
|
<width>0</width>
|
||||||
|
<height>100</height>
|
||||||
|
</size>
|
||||||
|
</property>
|
||||||
|
<property name="minimum">
|
||||||
|
<number>-2048</number>
|
||||||
|
</property>
|
||||||
|
<property name="maximum">
|
||||||
|
<number>2048</number>
|
||||||
|
</property>
|
||||||
|
<property name="orientation">
|
||||||
|
<enum>Qt::Vertical</enum>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="ModulationSlider" name="modulationSlider">
|
||||||
|
<property name="sizePolicy">
|
||||||
|
<sizepolicy hsizetype="Fixed" vsizetype="Fixed">
|
||||||
|
<horstretch>0</horstretch>
|
||||||
|
<verstretch>0</verstretch>
|
||||||
|
</sizepolicy>
|
||||||
|
</property>
|
||||||
|
<property name="minimumSize">
|
||||||
|
<size>
|
||||||
|
<width>0</width>
|
||||||
|
<height>100</height>
|
||||||
|
</size>
|
||||||
|
</property>
|
||||||
|
<property name="maximum">
|
||||||
|
<number>127</number>
|
||||||
|
</property>
|
||||||
|
<property name="orientation">
|
||||||
|
<enum>Qt::Vertical</enum>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="VelocitySlider" name="velocitySlider">
|
||||||
|
<property name="sizePolicy">
|
||||||
|
<sizepolicy hsizetype="Fixed" vsizetype="Fixed">
|
||||||
|
<horstretch>0</horstretch>
|
||||||
|
<verstretch>0</verstretch>
|
||||||
|
</sizepolicy>
|
||||||
|
</property>
|
||||||
|
<property name="minimumSize">
|
||||||
|
<size>
|
||||||
|
<width>0</width>
|
||||||
|
<height>100</height>
|
||||||
|
</size>
|
||||||
|
</property>
|
||||||
|
<property name="maximum">
|
||||||
|
<number>127</number>
|
||||||
|
</property>
|
||||||
|
<property name="value">
|
||||||
|
<number>90</number>
|
||||||
|
</property>
|
||||||
|
<property name="orientation">
|
||||||
|
<enum>Qt::Vertical</enum>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QScrollArea" name="keyboardScrollArea">
|
||||||
|
<property name="sizePolicy">
|
||||||
|
<sizepolicy hsizetype="Expanding" vsizetype="Fixed">
|
||||||
|
<horstretch>0</horstretch>
|
||||||
|
<verstretch>0</verstretch>
|
||||||
|
</sizepolicy>
|
||||||
|
</property>
|
||||||
|
<property name="minimumSize">
|
||||||
|
<size>
|
||||||
|
<width>500</width>
|
||||||
|
<height>100</height>
|
||||||
|
</size>
|
||||||
|
</property>
|
||||||
|
<property name="maximumSize">
|
||||||
|
<size>
|
||||||
|
<width>16777215</width>
|
||||||
|
<height>100</height>
|
||||||
|
</size>
|
||||||
|
</property>
|
||||||
|
<property name="frameShape">
|
||||||
|
<enum>QFrame::NoFrame</enum>
|
||||||
|
</property>
|
||||||
|
<property name="frameShadow">
|
||||||
|
<enum>QFrame::Plain</enum>
|
||||||
|
</property>
|
||||||
|
<property name="lineWidth">
|
||||||
|
<number>0</number>
|
||||||
|
</property>
|
||||||
|
<property name="widgetResizable">
|
||||||
|
<bool>true</bool>
|
||||||
|
</property>
|
||||||
|
<widget class="KeyboardWidget" name="keyboardContents">
|
||||||
|
<property name="geometry">
|
||||||
|
<rect>
|
||||||
|
<x>0</x>
|
||||||
|
<y>0</y>
|
||||||
|
<width>1501</width>
|
||||||
|
<height>85</height>
|
||||||
|
</rect>
|
||||||
|
</property>
|
||||||
|
<property name="sizePolicy">
|
||||||
|
<sizepolicy hsizetype="Fixed" vsizetype="Preferred">
|
||||||
|
<horstretch>0</horstretch>
|
||||||
|
<verstretch>0</verstretch>
|
||||||
|
</sizepolicy>
|
||||||
|
</property>
|
||||||
|
<property name="minimumSize">
|
||||||
|
<size>
|
||||||
|
<width>1501</width>
|
||||||
|
<height>0</height>
|
||||||
|
</size>
|
||||||
|
</property>
|
||||||
|
<property name="maximumSize">
|
||||||
|
<size>
|
||||||
|
<width>16777215</width>
|
||||||
|
<height>16777215</height>
|
||||||
|
</size>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</widget>
|
||||||
|
</widget>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</widget>
|
||||||
|
<widget class="QMenuBar" name="menubar">
|
||||||
|
<property name="geometry">
|
||||||
|
<rect>
|
||||||
|
<x>0</x>
|
||||||
|
<y>0</y>
|
||||||
|
<width>1360</width>
|
||||||
|
<height>27</height>
|
||||||
|
</rect>
|
||||||
|
</property>
|
||||||
|
<widget class="QMenu" name="menuFile">
|
||||||
|
<property name="title">
|
||||||
|
<string>&File</string>
|
||||||
|
</property>
|
||||||
|
<widget class="QMenu" name="menuRecent_Projects">
|
||||||
|
<property name="enabled">
|
||||||
|
<bool>false</bool>
|
||||||
|
</property>
|
||||||
|
<property name="title">
|
||||||
|
<string>Recent &Projects</string>
|
||||||
|
</property>
|
||||||
|
<property name="icon">
|
||||||
|
<iconset theme="document-open-recent"/>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
<addaction name="actionNew_Project"/>
|
||||||
|
<addaction name="actionOpen_Project"/>
|
||||||
|
<addaction name="menuRecent_Projects"/>
|
||||||
|
<addaction name="actionSave_Project"/>
|
||||||
|
<addaction name="actionRevert_Project"/>
|
||||||
|
<addaction name="actionReload_Sample_Data"/>
|
||||||
|
<addaction name="separator"/>
|
||||||
|
<addaction name="actionImport_Groups"/>
|
||||||
|
<addaction name="actionImport_Songs"/>
|
||||||
|
<addaction name="actionExport_GameCube_Groups"/>
|
||||||
|
<addaction name="actionImport_C_Headers"/>
|
||||||
|
<addaction name="actionExport_C_Headers"/>
|
||||||
|
<addaction name="separator"/>
|
||||||
|
<addaction name="actionQuit"/>
|
||||||
|
</widget>
|
||||||
|
<widget class="QMenu" name="menuProject">
|
||||||
|
<property name="title">
|
||||||
|
<string>Pro&ject</string>
|
||||||
|
</property>
|
||||||
|
<addaction name="actionNew_Subproject"/>
|
||||||
|
<addaction name="separator"/>
|
||||||
|
<addaction name="actionNew_SFX_Group"/>
|
||||||
|
<addaction name="actionNew_Song_Group"/>
|
||||||
|
<addaction name="separator"/>
|
||||||
|
<addaction name="actionNew_Sound_Macro"/>
|
||||||
|
<addaction name="actionNew_ADSR"/>
|
||||||
|
<addaction name="actionNew_Curve"/>
|
||||||
|
<addaction name="actionNew_Keymap"/>
|
||||||
|
<addaction name="actionNew_Layers"/>
|
||||||
|
</widget>
|
||||||
|
<widget class="QMenu" name="menuAudio">
|
||||||
|
<property name="title">
|
||||||
|
<string>&Audio</string>
|
||||||
|
</property>
|
||||||
|
<addaction name="separator"/>
|
||||||
|
<addaction name="actionSelect_Output_Device"/>
|
||||||
|
</widget>
|
||||||
|
<widget class="QMenu" name="menuMIDI">
|
||||||
|
<property name="title">
|
||||||
|
<string>&MIDI</string>
|
||||||
|
</property>
|
||||||
|
<addaction name="separator"/>
|
||||||
|
<addaction name="actionInput_Device"/>
|
||||||
|
</widget>
|
||||||
|
<widget class="QMenu" name="menuEdit">
|
||||||
|
<property name="title">
|
||||||
|
<string>&Edit</string>
|
||||||
|
</property>
|
||||||
|
<addaction name="actionCut"/>
|
||||||
|
<addaction name="actionCopy"/>
|
||||||
|
<addaction name="actionPaste"/>
|
||||||
|
<addaction name="actionDelete"/>
|
||||||
|
</widget>
|
||||||
|
<widget class="QMenu" name="menuHelp">
|
||||||
|
<property name="title">
|
||||||
|
<string>&Help</string>
|
||||||
|
</property>
|
||||||
|
<addaction name="actionAbout_Amuse"/>
|
||||||
|
<addaction name="actionAbout_Qt"/>
|
||||||
|
</widget>
|
||||||
|
<addaction name="menuFile"/>
|
||||||
|
<addaction name="menuEdit"/>
|
||||||
|
<addaction name="menuProject"/>
|
||||||
|
<addaction name="menuAudio"/>
|
||||||
|
<addaction name="menuMIDI"/>
|
||||||
|
<addaction name="menuHelp"/>
|
||||||
|
</widget>
|
||||||
|
<widget class="StatusBarWidget" name="statusbar"/>
|
||||||
|
<action name="actionNew_Project">
|
||||||
|
<property name="icon">
|
||||||
|
<iconset theme="document-new"/>
|
||||||
|
</property>
|
||||||
|
<property name="text">
|
||||||
|
<string>&New Project</string>
|
||||||
|
</property>
|
||||||
|
</action>
|
||||||
|
<action name="actionOpen_Project">
|
||||||
|
<property name="icon">
|
||||||
|
<iconset theme="document-open"/>
|
||||||
|
</property>
|
||||||
|
<property name="text">
|
||||||
|
<string>&Open Project</string>
|
||||||
|
</property>
|
||||||
|
</action>
|
||||||
|
<action name="actionCut">
|
||||||
|
<property name="enabled">
|
||||||
|
<bool>false</bool>
|
||||||
|
</property>
|
||||||
|
<property name="icon">
|
||||||
|
<iconset theme="edit-cut"/>
|
||||||
|
</property>
|
||||||
|
<property name="text">
|
||||||
|
<string>&Cut</string>
|
||||||
|
</property>
|
||||||
|
</action>
|
||||||
|
<action name="actionCopy">
|
||||||
|
<property name="enabled">
|
||||||
|
<bool>false</bool>
|
||||||
|
</property>
|
||||||
|
<property name="icon">
|
||||||
|
<iconset theme="edit-copy"/>
|
||||||
|
</property>
|
||||||
|
<property name="text">
|
||||||
|
<string>C&opy</string>
|
||||||
|
</property>
|
||||||
|
</action>
|
||||||
|
<action name="actionPaste">
|
||||||
|
<property name="enabled">
|
||||||
|
<bool>false</bool>
|
||||||
|
</property>
|
||||||
|
<property name="icon">
|
||||||
|
<iconset theme="edit-paste"/>
|
||||||
|
</property>
|
||||||
|
<property name="text">
|
||||||
|
<string>&Paste</string>
|
||||||
|
</property>
|
||||||
|
</action>
|
||||||
|
<action name="actionDelete">
|
||||||
|
<property name="enabled">
|
||||||
|
<bool>false</bool>
|
||||||
|
</property>
|
||||||
|
<property name="icon">
|
||||||
|
<iconset theme="edit-delete"/>
|
||||||
|
</property>
|
||||||
|
<property name="text">
|
||||||
|
<string>&Delete</string>
|
||||||
|
</property>
|
||||||
|
</action>
|
||||||
|
<action name="actionImport_Groups">
|
||||||
|
<property name="text">
|
||||||
|
<string>&Import Groups</string>
|
||||||
|
</property>
|
||||||
|
<property name="shortcut">
|
||||||
|
<string>Ctrl+I</string>
|
||||||
|
</property>
|
||||||
|
</action>
|
||||||
|
<action name="actionNew_SFX_Group">
|
||||||
|
<property name="enabled">
|
||||||
|
<bool>false</bool>
|
||||||
|
</property>
|
||||||
|
<property name="icon">
|
||||||
|
<iconset resource="resources/resources.qrc">
|
||||||
|
<normaloff>:/icons/IconNewSoundGroup.svg</normaloff>:/icons/IconNewSoundGroup.svg</iconset>
|
||||||
|
</property>
|
||||||
|
<property name="text">
|
||||||
|
<string>New SF&X Group</string>
|
||||||
|
</property>
|
||||||
|
</action>
|
||||||
|
<action name="actionNew_Song_Group">
|
||||||
|
<property name="enabled">
|
||||||
|
<bool>false</bool>
|
||||||
|
</property>
|
||||||
|
<property name="icon">
|
||||||
|
<iconset resource="resources/resources.qrc">
|
||||||
|
<normaloff>:/icons/IconNewSongGroup.svg</normaloff>:/icons/IconNewSongGroup.svg</iconset>
|
||||||
|
</property>
|
||||||
|
<property name="text">
|
||||||
|
<string>New Son&g Group</string>
|
||||||
|
</property>
|
||||||
|
</action>
|
||||||
|
<action name="actionNew_Sound_Macro">
|
||||||
|
<property name="enabled">
|
||||||
|
<bool>false</bool>
|
||||||
|
</property>
|
||||||
|
<property name="icon">
|
||||||
|
<iconset resource="resources/resources.qrc">
|
||||||
|
<normaloff>:/icons/IconNewSoundMacro.svg</normaloff>:/icons/IconNewSoundMacro.svg</iconset>
|
||||||
|
</property>
|
||||||
|
<property name="text">
|
||||||
|
<string>New Sound &Macro</string>
|
||||||
|
</property>
|
||||||
|
</action>
|
||||||
|
<action name="actionNew_Keymap">
|
||||||
|
<property name="enabled">
|
||||||
|
<bool>false</bool>
|
||||||
|
</property>
|
||||||
|
<property name="icon">
|
||||||
|
<iconset resource="resources/resources.qrc">
|
||||||
|
<normaloff>:/icons/IconNewKeymap.svg</normaloff>:/icons/IconNewKeymap.svg</iconset>
|
||||||
|
</property>
|
||||||
|
<property name="text">
|
||||||
|
<string>New &Keymap</string>
|
||||||
|
</property>
|
||||||
|
</action>
|
||||||
|
<action name="actionNew_Layers">
|
||||||
|
<property name="enabled">
|
||||||
|
<bool>false</bool>
|
||||||
|
</property>
|
||||||
|
<property name="icon">
|
||||||
|
<iconset resource="resources/resources.qrc">
|
||||||
|
<normaloff>:/icons/IconNewLayers.svg</normaloff>:/icons/IconNewLayers.svg</iconset>
|
||||||
|
</property>
|
||||||
|
<property name="text">
|
||||||
|
<string>New &Layers</string>
|
||||||
|
</property>
|
||||||
|
</action>
|
||||||
|
<action name="actionSelect_Output_Device">
|
||||||
|
<property name="enabled">
|
||||||
|
<bool>false</bool>
|
||||||
|
</property>
|
||||||
|
<property name="text">
|
||||||
|
<string>&Output Device:</string>
|
||||||
|
</property>
|
||||||
|
</action>
|
||||||
|
<action name="actionInput_Device">
|
||||||
|
<property name="enabled">
|
||||||
|
<bool>false</bool>
|
||||||
|
</property>
|
||||||
|
<property name="text">
|
||||||
|
<string>&Input Device:</string>
|
||||||
|
</property>
|
||||||
|
</action>
|
||||||
|
<action name="actionExport_GameCube_Groups">
|
||||||
|
<property name="enabled">
|
||||||
|
<bool>false</bool>
|
||||||
|
</property>
|
||||||
|
<property name="text">
|
||||||
|
<string>&Export GameCube Groups</string>
|
||||||
|
</property>
|
||||||
|
<property name="shortcut">
|
||||||
|
<string>Ctrl+E</string>
|
||||||
|
</property>
|
||||||
|
</action>
|
||||||
|
<action name="actionNew_Subproject">
|
||||||
|
<property name="enabled">
|
||||||
|
<bool>false</bool>
|
||||||
|
</property>
|
||||||
|
<property name="icon">
|
||||||
|
<iconset resource="resources/resources.qrc">
|
||||||
|
<normaloff>:/icons/IconNewGroup.svg</normaloff>:/icons/IconNewGroup.svg</iconset>
|
||||||
|
</property>
|
||||||
|
<property name="text">
|
||||||
|
<string>&New Subproject</string>
|
||||||
|
</property>
|
||||||
|
</action>
|
||||||
|
<action name="actionNew_ADSR">
|
||||||
|
<property name="enabled">
|
||||||
|
<bool>false</bool>
|
||||||
|
</property>
|
||||||
|
<property name="icon">
|
||||||
|
<iconset resource="resources/resources.qrc">
|
||||||
|
<normaloff>:/icons/IconNewADSR.svg</normaloff>:/icons/IconNewADSR.svg</iconset>
|
||||||
|
</property>
|
||||||
|
<property name="text">
|
||||||
|
<string>New &ADSR</string>
|
||||||
|
</property>
|
||||||
|
</action>
|
||||||
|
<action name="actionNew_Curve">
|
||||||
|
<property name="enabled">
|
||||||
|
<bool>false</bool>
|
||||||
|
</property>
|
||||||
|
<property name="icon">
|
||||||
|
<iconset resource="resources/resources.qrc">
|
||||||
|
<normaloff>:/icons/IconNewCurve.svg</normaloff>:/icons/IconNewCurve.svg</iconset>
|
||||||
|
</property>
|
||||||
|
<property name="text">
|
||||||
|
<string>New &Curve</string>
|
||||||
|
</property>
|
||||||
|
</action>
|
||||||
|
<action name="actionSave_Project">
|
||||||
|
<property name="enabled">
|
||||||
|
<bool>false</bool>
|
||||||
|
</property>
|
||||||
|
<property name="icon">
|
||||||
|
<iconset theme="document-save"/>
|
||||||
|
</property>
|
||||||
|
<property name="text">
|
||||||
|
<string>&Save Project</string>
|
||||||
|
</property>
|
||||||
|
</action>
|
||||||
|
<action name="actionRevert_Project">
|
||||||
|
<property name="enabled">
|
||||||
|
<bool>false</bool>
|
||||||
|
</property>
|
||||||
|
<property name="icon">
|
||||||
|
<iconset theme="document-revert"/>
|
||||||
|
</property>
|
||||||
|
<property name="text">
|
||||||
|
<string>&Revert Project</string>
|
||||||
|
</property>
|
||||||
|
</action>
|
||||||
|
<action name="actionReload_Sample_Data">
|
||||||
|
<property name="enabled">
|
||||||
|
<bool>false</bool>
|
||||||
|
</property>
|
||||||
|
<property name="text">
|
||||||
|
<string>Reload Sample &Data</string>
|
||||||
|
</property>
|
||||||
|
</action>
|
||||||
|
<action name="actionImport_Songs">
|
||||||
|
<property name="enabled">
|
||||||
|
<bool>false</bool>
|
||||||
|
</property>
|
||||||
|
<property name="text">
|
||||||
|
<string>I&mport Songs</string>
|
||||||
|
</property>
|
||||||
|
</action>
|
||||||
|
<action name="actionAbout_Amuse">
|
||||||
|
<property name="icon">
|
||||||
|
<iconset theme="help-about"/>
|
||||||
|
</property>
|
||||||
|
<property name="text">
|
||||||
|
<string>&About Amuse</string>
|
||||||
|
</property>
|
||||||
|
<property name="menuRole">
|
||||||
|
<enum>QAction::AboutRole</enum>
|
||||||
|
</property>
|
||||||
|
</action>
|
||||||
|
<action name="actionAbout_Qt">
|
||||||
|
<property name="icon">
|
||||||
|
<iconset theme="help-about"/>
|
||||||
|
</property>
|
||||||
|
<property name="text">
|
||||||
|
<string>About &Qt</string>
|
||||||
|
</property>
|
||||||
|
<property name="menuRole">
|
||||||
|
<enum>QAction::AboutQtRole</enum>
|
||||||
|
</property>
|
||||||
|
</action>
|
||||||
|
<action name="actionExport_C_Headers">
|
||||||
|
<property name="enabled">
|
||||||
|
<bool>false</bool>
|
||||||
|
</property>
|
||||||
|
<property name="text">
|
||||||
|
<string>Export &C Headers</string>
|
||||||
|
</property>
|
||||||
|
</action>
|
||||||
|
<action name="actionQuit">
|
||||||
|
<property name="icon">
|
||||||
|
<iconset theme="application-exit"/>
|
||||||
|
</property>
|
||||||
|
<property name="text">
|
||||||
|
<string>&Quit</string>
|
||||||
|
</property>
|
||||||
|
<property name="menuRole">
|
||||||
|
<enum>QAction::QuitRole</enum>
|
||||||
|
</property>
|
||||||
|
</action>
|
||||||
|
<action name="actionImport_C_Headers">
|
||||||
|
<property name="enabled">
|
||||||
|
<bool>false</bool>
|
||||||
|
</property>
|
||||||
|
<property name="text">
|
||||||
|
<string>Import C &Headers</string>
|
||||||
|
</property>
|
||||||
|
</action>
|
||||||
|
</widget>
|
||||||
|
<customwidgets>
|
||||||
|
<customwidget>
|
||||||
|
<class>KeyboardWidget</class>
|
||||||
|
<extends>QWidget</extends>
|
||||||
|
<header>KeyboardWidget.hpp</header>
|
||||||
|
<container>1</container>
|
||||||
|
</customwidget>
|
||||||
|
<customwidget>
|
||||||
|
<class>StatusBarWidget</class>
|
||||||
|
<extends>QStatusBar</extends>
|
||||||
|
<header>StatusBarWidget.hpp</header>
|
||||||
|
</customwidget>
|
||||||
|
<customwidget>
|
||||||
|
<class>ModulationSlider</class>
|
||||||
|
<extends>QSlider</extends>
|
||||||
|
<header>KeyboardWidget.hpp</header>
|
||||||
|
</customwidget>
|
||||||
|
<customwidget>
|
||||||
|
<class>PitchSlider</class>
|
||||||
|
<extends>QSlider</extends>
|
||||||
|
<header>KeyboardWidget.hpp</header>
|
||||||
|
</customwidget>
|
||||||
|
<customwidget>
|
||||||
|
<class>VelocitySlider</class>
|
||||||
|
<extends>QSlider</extends>
|
||||||
|
<header>KeyboardWidget.hpp</header>
|
||||||
|
</customwidget>
|
||||||
|
</customwidgets>
|
||||||
|
<resources>
|
||||||
|
<include location="resources/resources.qrc"/>
|
||||||
|
</resources>
|
||||||
|
<connections/>
|
||||||
|
</ui>
|
||||||
287
Editor/NewSoundMacroDialog.cpp
Normal file
@@ -0,0 +1,287 @@
|
|||||||
|
#include "NewSoundMacroDialog.hpp"
|
||||||
|
#include <QVBoxLayout>
|
||||||
|
#include <QLabel>
|
||||||
|
#include "amuse/Common.hpp"
|
||||||
|
|
||||||
|
static const uint32_t BasicMacro[] =
|
||||||
|
{
|
||||||
|
0x38000000, 0xC07A1000,
|
||||||
|
0x10000000, 0x00000000,
|
||||||
|
0x07010001, 0x0000FFFF,
|
||||||
|
0x11000000, 0x00000000,
|
||||||
|
0x31000000, 0x00000000,
|
||||||
|
0x00000000, 0x00000000,
|
||||||
|
};
|
||||||
|
|
||||||
|
static const uint32_t Looped[] =
|
||||||
|
{
|
||||||
|
0x38000000, 0xC07A1000,
|
||||||
|
0x10000000, 0x00000000,
|
||||||
|
0x07010001, 0x0000FFFF,
|
||||||
|
0x3000D08A, 0x00000000,
|
||||||
|
0x38000000, 0xE8030000,
|
||||||
|
0x0F000000, 0x0001E803,
|
||||||
|
0x07000001, 0x0000E803,
|
||||||
|
0x11000000, 0x00000000,
|
||||||
|
0x00000000, 0x00000000,
|
||||||
|
};
|
||||||
|
|
||||||
|
static const uint32_t LoopRelease[] =
|
||||||
|
{
|
||||||
|
0x38000000, 0xC07A1000,
|
||||||
|
0x10000000, 0x00000000,
|
||||||
|
0x1C000F01, 0x0001FA00,
|
||||||
|
0x07010000, 0x0000FFFF,
|
||||||
|
0x3000D08A, 0x00000000,
|
||||||
|
0x0F500000, 0x00013200,
|
||||||
|
0x07000000, 0x00003200,
|
||||||
|
0x38000000, 0xE8030000,
|
||||||
|
0x0F000000, 0x0001E803,
|
||||||
|
0x07000000, 0x0000E803,
|
||||||
|
0x11000000, 0x00000000,
|
||||||
|
0x00000000, 0x00000000,
|
||||||
|
};
|
||||||
|
|
||||||
|
static const uint32_t LoopSoftRelease[] =
|
||||||
|
{
|
||||||
|
0x38000000, 0xC07A1000,
|
||||||
|
0x10000000, 0x00000000,
|
||||||
|
0x1C000F01, 0x0001C800,
|
||||||
|
0x07010000, 0x0000FFFF,
|
||||||
|
0x3000D08A, 0x00000000,
|
||||||
|
0x0F600000, 0x00016400,
|
||||||
|
0x07000000, 0x00006400,
|
||||||
|
0x38000000, 0xE8030000,
|
||||||
|
0x0F000000, 0x0001E803,
|
||||||
|
0x07000000, 0x0000E803,
|
||||||
|
0x11000000, 0x00000000,
|
||||||
|
0x00000000, 0x00000000,
|
||||||
|
};
|
||||||
|
|
||||||
|
static const uint32_t LoopSoftReleaseNoClick[] =
|
||||||
|
{
|
||||||
|
0x38000000, 0xC07A1000,
|
||||||
|
0x147F0000, 0x00010100,
|
||||||
|
0x10000000, 0x00000000,
|
||||||
|
0x1C000F01, 0x0001C800,
|
||||||
|
0x07010000, 0x0000FFFF,
|
||||||
|
0x3000D08A, 0x00000000,
|
||||||
|
0x0F600000, 0x00016400,
|
||||||
|
0x07000000, 0x00006400,
|
||||||
|
0x38000000, 0xE8030000,
|
||||||
|
0x0F000000, 0x0001E803,
|
||||||
|
0x07000000, 0x0000E803,
|
||||||
|
0x11000000, 0x00000000,
|
||||||
|
0x00000000, 0x00000000,
|
||||||
|
};
|
||||||
|
|
||||||
|
static const uint32_t LoopADSR[] =
|
||||||
|
{
|
||||||
|
0x38000000, 0xC07A1000,
|
||||||
|
0x0C000000, 0x00000000,
|
||||||
|
0x10000000, 0x00000000,
|
||||||
|
0x1C000F01, 0x0001C800,
|
||||||
|
0x07010001, 0x0000FFFF,
|
||||||
|
0x3000D08A, 0x00000000,
|
||||||
|
0x12000000, 0x00000000,
|
||||||
|
0x07000001, 0x0000E803,
|
||||||
|
0x38000000, 0xE8030000,
|
||||||
|
0x07000001, 0x0000E803,
|
||||||
|
0x00000000, 0x00000000,
|
||||||
|
};
|
||||||
|
|
||||||
|
static const uint32_t LoopADSRSoftRelease[] =
|
||||||
|
{
|
||||||
|
0x38000000, 0xC07A1000,
|
||||||
|
0x0C000000, 0x00000000,
|
||||||
|
0x10000000, 0x00000000,
|
||||||
|
0x1C000F01, 0x0001C800,
|
||||||
|
0x07010001, 0x0000FFFF,
|
||||||
|
0x3000D08A, 0x00000000,
|
||||||
|
0x0F600000, 0x00017800,
|
||||||
|
0x07000001, 0x00007800,
|
||||||
|
0x12000000, 0x00000000,
|
||||||
|
0x38000000, 0xE8030000,
|
||||||
|
0x07000001, 0x0000E803,
|
||||||
|
0x00000000, 0x00000000,
|
||||||
|
};
|
||||||
|
|
||||||
|
static const uint32_t LoopHold[] =
|
||||||
|
{
|
||||||
|
0x38000000, 0xC07A1000,
|
||||||
|
0x10000000, 0x00000000,
|
||||||
|
0x1C000F01, 0x0001C800,
|
||||||
|
0x07010001, 0x0000FFFF,
|
||||||
|
0x3000D08A, 0x00000000,
|
||||||
|
0x0F600000, 0x00016400,
|
||||||
|
0x07000001, 0x00006400,
|
||||||
|
0x38000000, 0xE8030000,
|
||||||
|
0x0F000000, 0x0001E803,
|
||||||
|
0x07000001, 0x0000E803,
|
||||||
|
0x11000000, 0x00000000,
|
||||||
|
0x00000000, 0x00000000,
|
||||||
|
};
|
||||||
|
|
||||||
|
static const uint32_t OneShot[] =
|
||||||
|
{
|
||||||
|
0x38000000, 0xC07A1000,
|
||||||
|
0x10000000, 0x00000000,
|
||||||
|
0x07000001, 0x0000FFFF,
|
||||||
|
0x31000000, 0x00000000,
|
||||||
|
0x00000000, 0x00000000,
|
||||||
|
};
|
||||||
|
|
||||||
|
static const uint32_t OneShotFixedNote[] =
|
||||||
|
{
|
||||||
|
0x38000000, 0xC07A1000,
|
||||||
|
0x193C0000, 0x00010000,
|
||||||
|
0x10000000, 0x00000000,
|
||||||
|
0x07000001, 0x0000FFFF,
|
||||||
|
0x31000000, 0x00000000,
|
||||||
|
0x00000000, 0x00000000,
|
||||||
|
};
|
||||||
|
|
||||||
|
static const uint32_t OneShotNoClick[] =
|
||||||
|
{
|
||||||
|
0x38000000, 0xC07A1000,
|
||||||
|
0x147F0000, 0x00010100,
|
||||||
|
0x10000000, 0x00000000,
|
||||||
|
0x07000001, 0x0000FFFF,
|
||||||
|
0x31000000, 0x00000000,
|
||||||
|
0x00000000, 0x00000000,
|
||||||
|
};
|
||||||
|
|
||||||
|
static const uint32_t OneShotFixedNoClick[] =
|
||||||
|
{
|
||||||
|
0x38000000, 0xC07A1000,
|
||||||
|
0x147F0000, 0x00010100,
|
||||||
|
0x193C0000, 0x00010000,
|
||||||
|
0x10000000, 0x00000000,
|
||||||
|
0x07000001, 0x0000FFFF,
|
||||||
|
0x31000000, 0x00000000,
|
||||||
|
0x00000000, 0x00000000,
|
||||||
|
};
|
||||||
|
|
||||||
|
static const uint32_t Bubbles[] =
|
||||||
|
{
|
||||||
|
0x38000000, 0xC07A1000,
|
||||||
|
0x0D600000, 0x00010000,
|
||||||
|
0x10000000, 0x00000000,
|
||||||
|
0x1D08E803, 0x00010000,
|
||||||
|
0x1E0544FD, 0x00010000,
|
||||||
|
0x0F000000, 0x0001F401,
|
||||||
|
0x07000000, 0x0000F401,
|
||||||
|
0x11000000, 0x00000000,
|
||||||
|
0x31000000, 0x00000000,
|
||||||
|
0x00000000, 0x00000000,
|
||||||
|
};
|
||||||
|
|
||||||
|
static const uint32_t DownTrigger[] =
|
||||||
|
{
|
||||||
|
0x38000000, 0xC07A1000,
|
||||||
|
0x10000000, 0x00000000,
|
||||||
|
0x07000000, 0x00001200,
|
||||||
|
0x11000000, 0x00000000,
|
||||||
|
0x07000000, 0x00000100,
|
||||||
|
0x18FE0000, 0x00010000,
|
||||||
|
0x05000000, 0x01000C00,
|
||||||
|
0x0F000000, 0x00016400,
|
||||||
|
0x07000001, 0x00006400,
|
||||||
|
0x31000000, 0x00000000,
|
||||||
|
0x00000000, 0x00000000,
|
||||||
|
};
|
||||||
|
|
||||||
|
static const uint32_t LongFadeInAndStop[] =
|
||||||
|
{
|
||||||
|
0x38000000, 0xC07A1000,
|
||||||
|
0x147F0000, 0x0001E803,
|
||||||
|
0x10000000, 0x00000000,
|
||||||
|
0x07000001, 0x0000E803,
|
||||||
|
0x11000000, 0x00000000,
|
||||||
|
0x31000000, 0x00000000,
|
||||||
|
0x00000000, 0x00000000,
|
||||||
|
};
|
||||||
|
|
||||||
|
static const uint32_t FadeInAndStop[] =
|
||||||
|
{
|
||||||
|
0x38000000, 0xC07A1000,
|
||||||
|
0x147F0000, 0x0001C800,
|
||||||
|
0x10000000, 0x00000000,
|
||||||
|
0x07000001, 0x0000C800,
|
||||||
|
0x11000000, 0x00000000,
|
||||||
|
0x31000000, 0x00000000,
|
||||||
|
0x00000000, 0x00000000,
|
||||||
|
};
|
||||||
|
|
||||||
|
static const uint32_t RandomTrigger[] =
|
||||||
|
{
|
||||||
|
0x38000000, 0xC07A1000,
|
||||||
|
0x0F000000, 0x0001F401,
|
||||||
|
0x195A0000, 0x00010000,
|
||||||
|
0x10000000, 0x00000000,
|
||||||
|
0x1750005A, 0x01000000,
|
||||||
|
0x07000001, 0x00002300,
|
||||||
|
0x05000000, 0x03001400,
|
||||||
|
0x11000000, 0x00000000,
|
||||||
|
0x31000000, 0x00000000,
|
||||||
|
0x00000000, 0x00000000,
|
||||||
|
};
|
||||||
|
|
||||||
|
static const uint32_t SimplePlaySample[] =
|
||||||
|
{
|
||||||
|
0x10000000, 0x00000000,
|
||||||
|
0x00000000, 0x00000000,
|
||||||
|
};
|
||||||
|
|
||||||
|
static const SoundMacroTemplateEntry Entries[] =
|
||||||
|
{
|
||||||
|
{QT_TRANSLATE_NOOP("NewSoundMacroDialog", "Basic Macro"), sizeof(BasicMacro), BasicMacro},
|
||||||
|
{QT_TRANSLATE_NOOP("NewSoundMacroDialog", "Looped"), sizeof(Looped), Looped},
|
||||||
|
{QT_TRANSLATE_NOOP("NewSoundMacroDialog", "Loop Release"), sizeof(LoopRelease), LoopRelease},
|
||||||
|
{QT_TRANSLATE_NOOP("NewSoundMacroDialog", "Loop Soft Release"), sizeof(LoopSoftRelease), LoopSoftRelease},
|
||||||
|
{QT_TRANSLATE_NOOP("NewSoundMacroDialog", "Loop Soft Release No Click"), sizeof(LoopSoftReleaseNoClick), LoopSoftReleaseNoClick},
|
||||||
|
{QT_TRANSLATE_NOOP("NewSoundMacroDialog", "Loop ADSR"), sizeof(LoopADSR), LoopADSR},
|
||||||
|
{QT_TRANSLATE_NOOP("NewSoundMacroDialog", "Loop ADSR Soft Release"), sizeof(LoopADSRSoftRelease), LoopADSRSoftRelease},
|
||||||
|
{QT_TRANSLATE_NOOP("NewSoundMacroDialog", "Loop Hold"), sizeof(LoopHold), LoopHold},
|
||||||
|
{QT_TRANSLATE_NOOP("NewSoundMacroDialog", "One-Shot"), sizeof(OneShot), OneShot},
|
||||||
|
{QT_TRANSLATE_NOOP("NewSoundMacroDialog", "One-Shot Fixed Note"), sizeof(OneShotFixedNote), OneShotFixedNote},
|
||||||
|
{QT_TRANSLATE_NOOP("NewSoundMacroDialog", "One-Shot No Click"), sizeof(OneShotNoClick), OneShotNoClick},
|
||||||
|
{QT_TRANSLATE_NOOP("NewSoundMacroDialog", "One-Shot Fixed No Click"), sizeof(OneShotFixedNoClick), OneShotFixedNoClick},
|
||||||
|
{QT_TRANSLATE_NOOP("NewSoundMacroDialog", "Bubbles"), sizeof(Bubbles), Bubbles},
|
||||||
|
{QT_TRANSLATE_NOOP("NewSoundMacroDialog", "Down Trigger"), sizeof(DownTrigger), DownTrigger},
|
||||||
|
{QT_TRANSLATE_NOOP("NewSoundMacroDialog", "Long Fade in and Stop"), sizeof(LongFadeInAndStop), LongFadeInAndStop},
|
||||||
|
{QT_TRANSLATE_NOOP("NewSoundMacroDialog", "Fade in and Stop"), sizeof(FadeInAndStop), FadeInAndStop},
|
||||||
|
{QT_TRANSLATE_NOOP("NewSoundMacroDialog", "Random Trigger"), sizeof(RandomTrigger), RandomTrigger},
|
||||||
|
{QT_TRANSLATE_NOOP("NewSoundMacroDialog", "Simple Play Sample"), sizeof(SimplePlaySample), SimplePlaySample}
|
||||||
|
};
|
||||||
|
|
||||||
|
const SoundMacroTemplateEntry* NewSoundMacroDialog::getSelectedTemplate() const
|
||||||
|
{
|
||||||
|
return &Entries[m_combo.currentIndex()];
|
||||||
|
}
|
||||||
|
|
||||||
|
NewSoundMacroDialog::NewSoundMacroDialog(const QString& groupName, QWidget* parent)
|
||||||
|
: QDialog(parent),
|
||||||
|
m_le(QString::fromStdString(amuse::SoundMacroId::CurNameDB->generateDefaultName(amuse::NameDB::Type::SoundMacro))),
|
||||||
|
m_buttonBox(QDialogButtonBox::Ok | QDialogButtonBox::Cancel, Qt::Horizontal)
|
||||||
|
{
|
||||||
|
setWindowTitle(tr("New Sound Macro"));
|
||||||
|
|
||||||
|
int idx = 0;
|
||||||
|
for (const auto& ent : Entries)
|
||||||
|
m_combo.addItem(tr(ent.m_name), idx++);
|
||||||
|
m_combo.setCurrentIndex(0);
|
||||||
|
|
||||||
|
QObject::connect(&m_buttonBox, SIGNAL(accepted()), this, SLOT(accept()));
|
||||||
|
QObject::connect(&m_buttonBox, SIGNAL(rejected()), this, SLOT(reject()));
|
||||||
|
|
||||||
|
QVBoxLayout* layout = new QVBoxLayout;
|
||||||
|
|
||||||
|
layout->addWidget(new QLabel(tr("What should the new macro in %1 be named?").arg(groupName)));
|
||||||
|
layout->addWidget(&m_le);
|
||||||
|
layout->addWidget(new QLabel(tr("Sound Macro Template")));
|
||||||
|
layout->addWidget(&m_combo);
|
||||||
|
layout->addWidget(&m_buttonBox);
|
||||||
|
|
||||||
|
setLayout(layout);
|
||||||
|
}
|
||||||
28
Editor/NewSoundMacroDialog.hpp
Normal file
@@ -0,0 +1,28 @@
|
|||||||
|
#ifndef AMUSE_NEW_SOUND_MACRO_DIALOG_HPP
|
||||||
|
#define AMUSE_NEW_SOUND_MACRO_DIALOG_HPP
|
||||||
|
|
||||||
|
#include <QDialog>
|
||||||
|
#include <QLineEdit>
|
||||||
|
#include <QComboBox>
|
||||||
|
#include <QDialogButtonBox>
|
||||||
|
|
||||||
|
struct SoundMacroTemplateEntry
|
||||||
|
{
|
||||||
|
const char* m_name;
|
||||||
|
size_t m_length;
|
||||||
|
const uint32_t* m_data;
|
||||||
|
};
|
||||||
|
|
||||||
|
class NewSoundMacroDialog : public QDialog
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
QLineEdit m_le;
|
||||||
|
QComboBox m_combo;
|
||||||
|
QDialogButtonBox m_buttonBox;
|
||||||
|
public:
|
||||||
|
explicit NewSoundMacroDialog(const QString& groupName, QWidget* parent = Q_NULLPTR);
|
||||||
|
QString getName() const { return m_le.text(); }
|
||||||
|
const SoundMacroTemplateEntry* getSelectedTemplate() const;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // AMUSE_NEW_SOUND_MACRO_DIALOG_HPP
|
||||||
2373
Editor/ProjectModel.cpp
Normal file
516
Editor/ProjectModel.hpp
Normal file
@@ -0,0 +1,516 @@
|
|||||||
|
#ifndef AMUSE_PROJECT_MODEL_HPP
|
||||||
|
#define AMUSE_PROJECT_MODEL_HPP
|
||||||
|
|
||||||
|
#include <QAbstractItemModel>
|
||||||
|
#include <QIdentityProxyModel>
|
||||||
|
#include <QSortFilterProxyModel>
|
||||||
|
#include <QDir>
|
||||||
|
#include <QIcon>
|
||||||
|
#include <map>
|
||||||
|
#include "Common.hpp"
|
||||||
|
#include "NewSoundMacroDialog.hpp"
|
||||||
|
#include "amuse/AudioGroup.hpp"
|
||||||
|
#include "amuse/AudioGroupData.hpp"
|
||||||
|
#include "amuse/AudioGroupProject.hpp"
|
||||||
|
#include "amuse/AudioGroupPool.hpp"
|
||||||
|
#include "amuse/AudioGroupSampleDirectory.hpp"
|
||||||
|
|
||||||
|
class ProjectModel;
|
||||||
|
class EditorUndoCommand;
|
||||||
|
|
||||||
|
enum AmuseItemEditFlags
|
||||||
|
{
|
||||||
|
AmuseItemNone = 0,
|
||||||
|
AmuseItemCut = 1,
|
||||||
|
AmuseItemCopy = 2,
|
||||||
|
AmuseItemPaste = 4,
|
||||||
|
AmuseItemDelete = 8,
|
||||||
|
AmuseItemNoCut = (AmuseItemCopy | AmuseItemPaste | AmuseItemDelete),
|
||||||
|
AmuseItemAll = (AmuseItemCut | AmuseItemCopy | AmuseItemPaste | AmuseItemDelete)
|
||||||
|
};
|
||||||
|
|
||||||
|
class OutlineFilterProxyModel : public QSortFilterProxyModel
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
QRegExp m_usageKey;
|
||||||
|
public:
|
||||||
|
explicit OutlineFilterProxyModel(ProjectModel* source);
|
||||||
|
public slots:
|
||||||
|
void setFilterRegExp(const QString &pattern);
|
||||||
|
bool filterAcceptsRow(int sourceRow, const QModelIndex &sourceParent) const;
|
||||||
|
};
|
||||||
|
|
||||||
|
class NullItemProxyModel : public QIdentityProxyModel
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
public:
|
||||||
|
explicit NullItemProxyModel(ProjectModel* source);
|
||||||
|
QModelIndex mapFromSource(const QModelIndex& sourceIndex) const;
|
||||||
|
QModelIndex mapToSource(const QModelIndex& proxyIndex) const;
|
||||||
|
int rowCount(const QModelIndex& parent) const;
|
||||||
|
QModelIndex index(int row, int column, const QModelIndex& parent) const;
|
||||||
|
QVariant data(const QModelIndex& proxyIndex, int role) const;
|
||||||
|
};
|
||||||
|
|
||||||
|
class PageObjectProxyModel : public QIdentityProxyModel
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
public:
|
||||||
|
explicit PageObjectProxyModel(ProjectModel* source);
|
||||||
|
QModelIndex mapFromSource(const QModelIndex& sourceIndex) const;
|
||||||
|
QModelIndex mapToSource(const QModelIndex& proxyIndex) const;
|
||||||
|
QModelIndex parent(const QModelIndex& child) const;
|
||||||
|
int rowCount(const QModelIndex& parent) const;
|
||||||
|
QModelIndex index(int row, int column, const QModelIndex& parent) const;
|
||||||
|
QVariant data(const QModelIndex& proxyIndex, int role) const;
|
||||||
|
Qt::ItemFlags flags(const QModelIndex& proxyIndex) const;
|
||||||
|
};
|
||||||
|
|
||||||
|
class ProjectModel : public QAbstractItemModel
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
public:
|
||||||
|
enum class ImportMode
|
||||||
|
{
|
||||||
|
Original,
|
||||||
|
WAVs,
|
||||||
|
Both
|
||||||
|
};
|
||||||
|
|
||||||
|
struct NameUndoRegistry
|
||||||
|
{
|
||||||
|
std::unordered_map<amuse::SongId, std::string> m_songIDs;
|
||||||
|
std::unordered_map<amuse::SFXId, std::string> m_sfxIDs;
|
||||||
|
void registerSongName(amuse::SongId id) const;
|
||||||
|
void unregisterSongName(amuse::SongId id);
|
||||||
|
void registerSFXName(amuse::SongId id) const;
|
||||||
|
void unregisterSFXName(amuse::SongId id);
|
||||||
|
void clear()
|
||||||
|
{
|
||||||
|
m_songIDs.clear();
|
||||||
|
m_sfxIDs.clear();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
private:
|
||||||
|
QDir m_dir;
|
||||||
|
OutlineFilterProxyModel m_outlineProxy;
|
||||||
|
NullItemProxyModel m_nullProxy;
|
||||||
|
PageObjectProxyModel m_pageObjectProxy;
|
||||||
|
|
||||||
|
amuse::ProjectDatabase m_projectDatabase;
|
||||||
|
std::unordered_map<QString, std::unique_ptr<amuse::AudioGroupDatabase>> m_groups;
|
||||||
|
|
||||||
|
struct Song
|
||||||
|
{
|
||||||
|
QString m_path;
|
||||||
|
int m_refCount = 0;
|
||||||
|
};
|
||||||
|
std::unordered_map<amuse::SongId, Song> m_midiFiles;
|
||||||
|
|
||||||
|
public:
|
||||||
|
class INode : public amuse::IObj
|
||||||
|
{
|
||||||
|
friend class ProjectModel;
|
||||||
|
virtual void _sortChildren();
|
||||||
|
public:
|
||||||
|
enum class Type
|
||||||
|
{
|
||||||
|
Null,
|
||||||
|
Root,
|
||||||
|
Group, // Top-level group
|
||||||
|
SongGroup,
|
||||||
|
SoundGroup,
|
||||||
|
Collection, // Classified object collection, one of the following:
|
||||||
|
SoundMacro,
|
||||||
|
ADSR,
|
||||||
|
Curve,
|
||||||
|
Keymap,
|
||||||
|
Layer,
|
||||||
|
Sample
|
||||||
|
};
|
||||||
|
protected:
|
||||||
|
QString m_name;
|
||||||
|
INode* m_parent = nullptr;
|
||||||
|
int m_row = -1;
|
||||||
|
std::vector<amuse::IObjToken<INode>> m_children;
|
||||||
|
amuse::IObjToken<INode> m_nullChild;
|
||||||
|
public:
|
||||||
|
virtual ~INode() = default;
|
||||||
|
INode(const QString& name);
|
||||||
|
INode(INode* parent) : m_parent(parent), m_row(0)
|
||||||
|
{
|
||||||
|
/* ONLY USED BY NULL NODE! */
|
||||||
|
}
|
||||||
|
|
||||||
|
int childCount() const { return int(m_children.size()); }
|
||||||
|
INode* child(int row) const
|
||||||
|
{
|
||||||
|
if (row == m_children.size())
|
||||||
|
return nullChild();
|
||||||
|
return m_children[row].get();
|
||||||
|
}
|
||||||
|
INode* nullChild() const { return m_nullChild.get(); }
|
||||||
|
INode* parent() const { return m_parent; }
|
||||||
|
int row() const { return m_row; }
|
||||||
|
|
||||||
|
void reindexRows(int row)
|
||||||
|
{
|
||||||
|
for (auto it = m_children.begin() + row; it != m_children.end(); ++it)
|
||||||
|
(*it)->m_row = row++;
|
||||||
|
m_nullChild->m_row = row;
|
||||||
|
}
|
||||||
|
|
||||||
|
void insertChild(amuse::ObjToken<INode> n)
|
||||||
|
{
|
||||||
|
assert(n->m_parent == nullptr && "Inserting already-parented node");
|
||||||
|
n->m_parent = this;
|
||||||
|
int row = hypotheticalIndex(n->name());
|
||||||
|
m_children.insert(m_children.begin() + row, n.get());
|
||||||
|
reindexRows(row);
|
||||||
|
}
|
||||||
|
amuse::ObjToken<INode> removeChild(INode* n)
|
||||||
|
{
|
||||||
|
amuse::ObjToken<INode> ret = n;
|
||||||
|
int row = ret->row();
|
||||||
|
assert(ret.get() == m_children.at(row).get() && "Removing non-child from node");
|
||||||
|
m_children.erase(m_children.begin() + row);
|
||||||
|
reindexRows(row);
|
||||||
|
ret->m_parent = nullptr;
|
||||||
|
ret->m_row = -1;
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
void reserve(size_t sz) { m_children.reserve(sz); }
|
||||||
|
template<class T, class... _Args>
|
||||||
|
T& makeChild(_Args&&... args)
|
||||||
|
{
|
||||||
|
auto tok = amuse::MakeObj<T>(std::forward<_Args>(args)...);
|
||||||
|
insertChild(tok.get());
|
||||||
|
return static_cast<T&>(*tok);
|
||||||
|
}
|
||||||
|
template<class T, class... _Args>
|
||||||
|
T& _appendChild(_Args&&... args)
|
||||||
|
{
|
||||||
|
auto tok = amuse::MakeObj<T>(std::forward<_Args>(args)...);
|
||||||
|
tok->m_parent = this;
|
||||||
|
tok->m_row = m_children.size();
|
||||||
|
m_children.push_back(tok.get());
|
||||||
|
m_nullChild->m_row = m_children.size();
|
||||||
|
return static_cast<T&>(*tok);
|
||||||
|
}
|
||||||
|
|
||||||
|
INode* findChild(const QString& name) const
|
||||||
|
{
|
||||||
|
int idx = hypotheticalIndex(name);
|
||||||
|
if (idx >= m_children.size())
|
||||||
|
return nullptr;
|
||||||
|
INode* ret = m_children[idx].get();
|
||||||
|
if (ret->name() == name)
|
||||||
|
return ret;
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool depthTraverse(const std::function<bool(INode* node)>& func)
|
||||||
|
{
|
||||||
|
for (auto& n : m_children)
|
||||||
|
if (!n->depthTraverse(func))
|
||||||
|
break;
|
||||||
|
return func(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool oneLevelTraverse(const std::function<bool(INode* node)>& func)
|
||||||
|
{
|
||||||
|
for (auto& n : m_children)
|
||||||
|
if (!func(n.get()))
|
||||||
|
return false;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
const QString& name() const { return m_name; }
|
||||||
|
virtual int hypotheticalIndex(const QString& name) const;
|
||||||
|
|
||||||
|
virtual amuse::NameDB* getNameDb() const { return nullptr; }
|
||||||
|
|
||||||
|
virtual Type type() const = 0;
|
||||||
|
virtual QString text() const = 0;
|
||||||
|
virtual QIcon icon() const = 0;
|
||||||
|
virtual Qt::ItemFlags flags() const { return Qt::ItemIsEnabled | Qt::ItemIsSelectable | Qt::ItemIsEditable; }
|
||||||
|
virtual AmuseItemEditFlags editFlags() const { return AmuseItemNone; }
|
||||||
|
|
||||||
|
virtual void registerNames(const NameUndoRegistry& registry) const {}
|
||||||
|
virtual void unregisterNames(NameUndoRegistry& registry) const {}
|
||||||
|
};
|
||||||
|
struct NullNode final : INode
|
||||||
|
{
|
||||||
|
NullNode(INode* parent) : INode(parent) {}
|
||||||
|
|
||||||
|
Type type() const { return Type::Null; }
|
||||||
|
QString text() const { return {}; }
|
||||||
|
QIcon icon() const { return {}; }
|
||||||
|
};
|
||||||
|
struct RootNode final : INode
|
||||||
|
{
|
||||||
|
RootNode() : INode(QStringLiteral("<root>")) {}
|
||||||
|
|
||||||
|
Type type() const { return Type::Root; }
|
||||||
|
QString text() const { return {}; }
|
||||||
|
QIcon icon() const { return {}; }
|
||||||
|
Qt::ItemFlags flags() const { return Qt::ItemIsEnabled; }
|
||||||
|
};
|
||||||
|
struct CollectionNode;
|
||||||
|
struct BasePoolObjectNode;
|
||||||
|
struct GroupNode final : INode
|
||||||
|
{
|
||||||
|
std::unordered_map<QString, std::unique_ptr<amuse::AudioGroupDatabase>>::iterator m_it;
|
||||||
|
GroupNode(const QString& name) : INode(name) {}
|
||||||
|
GroupNode(std::unordered_map<QString, std::unique_ptr<amuse::AudioGroupDatabase>>::iterator it)
|
||||||
|
: INode(it->first), m_it(it) {}
|
||||||
|
|
||||||
|
int hypotheticalIndex(const QString& name) const;
|
||||||
|
void _sortChildren();
|
||||||
|
|
||||||
|
static QIcon Icon;
|
||||||
|
Type type() const { return Type::Group; }
|
||||||
|
QString text() const { return m_name; }
|
||||||
|
QIcon icon() const { return Icon; }
|
||||||
|
AmuseItemEditFlags editFlags() const { return AmuseItemNoCut; }
|
||||||
|
|
||||||
|
CollectionNode* getCollectionOfType(Type tp) const;
|
||||||
|
amuse::AudioGroupDatabase* getAudioGroup() const { return m_it->second.get(); }
|
||||||
|
BasePoolObjectNode* pageObjectNodeOfId(amuse::ObjectId id) const;
|
||||||
|
};
|
||||||
|
struct SongGroupNode final : INode
|
||||||
|
{
|
||||||
|
amuse::GroupId m_id;
|
||||||
|
amuse::ObjToken<amuse::SongGroupIndex> m_index;
|
||||||
|
SongGroupNode(const QString& name, amuse::ObjToken<amuse::SongGroupIndex> index)
|
||||||
|
: INode(name), m_index(index) {}
|
||||||
|
SongGroupNode(amuse::GroupId id, amuse::ObjToken<amuse::SongGroupIndex> index)
|
||||||
|
: INode(amuse::GroupId::CurNameDB->resolveNameFromId(id).data()), m_id(id), m_index(index) {}
|
||||||
|
|
||||||
|
static QIcon Icon;
|
||||||
|
Type type() const { return Type::SongGroup; }
|
||||||
|
QString text() const { return m_name; }
|
||||||
|
QIcon icon() const { return Icon; }
|
||||||
|
AmuseItemEditFlags editFlags() const { return AmuseItemAll; }
|
||||||
|
|
||||||
|
amuse::NameDB* getNameDb() const { return amuse::GroupId::CurNameDB; }
|
||||||
|
|
||||||
|
void registerNames(const NameUndoRegistry& registry) const
|
||||||
|
{
|
||||||
|
amuse::GroupId::CurNameDB->registerPair(text().toUtf8().data(), m_id);
|
||||||
|
for (auto& p : m_index->m_midiSetups)
|
||||||
|
registry.registerSongName(p.first);
|
||||||
|
}
|
||||||
|
void unregisterNames(NameUndoRegistry& registry) const
|
||||||
|
{
|
||||||
|
amuse::GroupId::CurNameDB->remove(m_id);
|
||||||
|
for (auto& p : m_index->m_midiSetups)
|
||||||
|
registry.unregisterSongName(p.first);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
struct SoundGroupNode final : INode
|
||||||
|
{
|
||||||
|
amuse::GroupId m_id;
|
||||||
|
amuse::ObjToken<amuse::SFXGroupIndex> m_index;
|
||||||
|
SoundGroupNode(const QString& name, amuse::ObjToken<amuse::SFXGroupIndex> index)
|
||||||
|
: INode(name), m_index(index) {}
|
||||||
|
SoundGroupNode(amuse::GroupId id, amuse::ObjToken<amuse::SFXGroupIndex> index)
|
||||||
|
: INode(amuse::GroupId::CurNameDB->resolveNameFromId(id).data()), m_id(id), m_index(index) {}
|
||||||
|
|
||||||
|
static QIcon Icon;
|
||||||
|
Type type() const { return Type::SoundGroup; }
|
||||||
|
QString text() const { return m_name; }
|
||||||
|
QIcon icon() const { return Icon; }
|
||||||
|
AmuseItemEditFlags editFlags() const { return AmuseItemAll; }
|
||||||
|
|
||||||
|
amuse::NameDB* getNameDb() const { return amuse::GroupId::CurNameDB; }
|
||||||
|
|
||||||
|
void registerNames(const NameUndoRegistry& registry) const
|
||||||
|
{
|
||||||
|
amuse::GroupId::CurNameDB->registerPair(text().toUtf8().data(), m_id);
|
||||||
|
for (auto& p : m_index->m_sfxEntries)
|
||||||
|
registry.registerSFXName(p.first);
|
||||||
|
}
|
||||||
|
void unregisterNames(NameUndoRegistry& registry) const
|
||||||
|
{
|
||||||
|
amuse::GroupId::CurNameDB->remove(m_id);
|
||||||
|
for (auto& p : m_index->m_sfxEntries)
|
||||||
|
registry.unregisterSFXName(p.first);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
struct CollectionNode final : INode
|
||||||
|
{
|
||||||
|
QIcon m_icon;
|
||||||
|
Type m_collectionType;
|
||||||
|
CollectionNode(const QString& name, const QIcon& icon, Type collectionType)
|
||||||
|
: INode(name), m_icon(icon), m_collectionType(collectionType) {}
|
||||||
|
|
||||||
|
Type type() const { return Type::Collection; }
|
||||||
|
QString text() const { return m_name; }
|
||||||
|
QIcon icon() const { return m_icon; }
|
||||||
|
Qt::ItemFlags flags() const { return Qt::ItemIsEnabled; }
|
||||||
|
|
||||||
|
Type collectionType() const { return m_collectionType; }
|
||||||
|
int indexOfId(amuse::ObjectId id) const;
|
||||||
|
amuse::ObjectId idOfIndex(int idx) const;
|
||||||
|
BasePoolObjectNode* nodeOfIndex(int idx) const;
|
||||||
|
BasePoolObjectNode* nodeOfId(amuse::ObjectId id) const;
|
||||||
|
};
|
||||||
|
struct BasePoolObjectNode : INode
|
||||||
|
{
|
||||||
|
amuse::ObjectId m_id;
|
||||||
|
BasePoolObjectNode(const QString& name) : INode(name) {}
|
||||||
|
BasePoolObjectNode(amuse::ObjectId id, const QString& name)
|
||||||
|
: INode(name), m_id(id) {}
|
||||||
|
amuse::ObjectId id() const { return m_id; }
|
||||||
|
QString text() const { return m_name; }
|
||||||
|
QIcon icon() const { return {}; }
|
||||||
|
};
|
||||||
|
template <class ID, class T, INode::Type TP>
|
||||||
|
struct PoolObjectNode final : BasePoolObjectNode
|
||||||
|
{
|
||||||
|
amuse::ObjToken<T> m_obj;
|
||||||
|
PoolObjectNode(const QString& name, amuse::ObjToken<T> obj) : BasePoolObjectNode(name), m_obj(obj) {}
|
||||||
|
PoolObjectNode(ID id, amuse::ObjToken<T> obj)
|
||||||
|
: BasePoolObjectNode(id, ID::CurNameDB->resolveNameFromId(id).data()), m_obj(obj) {}
|
||||||
|
|
||||||
|
Type type() const { return TP; }
|
||||||
|
AmuseItemEditFlags editFlags() const { return TP == INode::Type::Sample ? AmuseItemNoCut : AmuseItemAll; }
|
||||||
|
|
||||||
|
void registerNames(const NameUndoRegistry& registry) const
|
||||||
|
{
|
||||||
|
ID::CurNameDB->registerPair(text().toUtf8().data(), m_id);
|
||||||
|
}
|
||||||
|
void unregisterNames(NameUndoRegistry& registry) const
|
||||||
|
{
|
||||||
|
ID::CurNameDB->remove(m_id);
|
||||||
|
}
|
||||||
|
amuse::NameDB* getNameDb() const
|
||||||
|
{
|
||||||
|
return ID::CurNameDB;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
using SoundMacroNode = PoolObjectNode<amuse::SoundMacroId, amuse::SoundMacro, INode::Type::SoundMacro>;
|
||||||
|
using ADSRNode = PoolObjectNode<amuse::TableId, std::unique_ptr<amuse::ITable>, INode::Type::ADSR>;
|
||||||
|
using CurveNode = PoolObjectNode<amuse::TableId, std::unique_ptr<amuse::ITable>, INode::Type::Curve>;
|
||||||
|
using KeymapNode = PoolObjectNode<amuse::KeymapId, std::array<amuse::Keymap, 128>, INode::Type::Keymap>;
|
||||||
|
using LayersNode = PoolObjectNode<amuse::LayersId, std::vector<amuse::LayerMapping>, INode::Type::Layer>;
|
||||||
|
using SampleNode = PoolObjectNode<amuse::SampleId, amuse::SampleEntry, INode::Type::Sample>;
|
||||||
|
|
||||||
|
amuse::ObjToken<RootNode> m_root;
|
||||||
|
|
||||||
|
bool m_needsReset = false;
|
||||||
|
void _buildGroupNodeCollections(GroupNode& gn);
|
||||||
|
void _buildGroupNode(GroupNode& gn, amuse::AudioGroup& group);
|
||||||
|
void _resetModelData();
|
||||||
|
void _resetSongRefCount();
|
||||||
|
QString MakeDedupedSubprojectName(const QString& origName);
|
||||||
|
static QString MakeDedupedName(const QString& origName, amuse::NameDB* db);
|
||||||
|
|
||||||
|
public:
|
||||||
|
explicit ProjectModel(const QString& path, QObject* parent = Q_NULLPTR);
|
||||||
|
|
||||||
|
bool clearProjectData();
|
||||||
|
bool openGroupData(const QString& groupName, UIMessenger& messenger);
|
||||||
|
void openSongsData();
|
||||||
|
void importSongsData(const QString& path);
|
||||||
|
bool reloadSampleData(const QString& groupName, UIMessenger& messenger);
|
||||||
|
bool importGroupData(const QString& groupName, const amuse::AudioGroupData& data,
|
||||||
|
ImportMode mode, UIMessenger& messenger);
|
||||||
|
void saveSongsIndex();
|
||||||
|
bool saveToFile(UIMessenger& messenger);
|
||||||
|
QStringList getGroupList() const;
|
||||||
|
bool exportGroup(const QString& path, const QString& groupName, UIMessenger& messenger) const;
|
||||||
|
bool importHeader(const QString& path, const QString& groupName, UIMessenger& messenger) const;
|
||||||
|
bool exportHeader(const QString& path, const QString& groupName, bool& yesToAll, UIMessenger& messenger) const;
|
||||||
|
|
||||||
|
void updateNodeNames();
|
||||||
|
bool ensureModelData();
|
||||||
|
|
||||||
|
QModelIndex proxyCreateIndex(int arow, int acolumn, void *adata) const;
|
||||||
|
QModelIndex index(int row, int column, const QModelIndex& parent = QModelIndex()) const;
|
||||||
|
QModelIndex index(INode* node) const;
|
||||||
|
QModelIndex parent(const QModelIndex& child) const;
|
||||||
|
int rowCount(const QModelIndex& parent = QModelIndex()) const;
|
||||||
|
int columnCount(const QModelIndex& parent = QModelIndex()) const;
|
||||||
|
QVariant data(const QModelIndex& index, int role = Qt::DisplayRole) const;
|
||||||
|
bool setData(const QModelIndex& index, const QVariant& value, int role = Qt::EditRole);
|
||||||
|
Qt::ItemFlags flags(const QModelIndex& index) const;
|
||||||
|
INode* node(const QModelIndex& index) const;
|
||||||
|
GroupNode* getGroupNode(INode* node) const;
|
||||||
|
AmuseItemEditFlags editFlags(const QModelIndex& index) const;
|
||||||
|
RootNode* rootNode() const { return m_root.get(); }
|
||||||
|
|
||||||
|
void _postAddNode(INode* n, const NameUndoRegistry& registry);
|
||||||
|
void _preDelNode(INode* n, NameUndoRegistry& registry);
|
||||||
|
void _addNode(GroupNode* node, std::unique_ptr<amuse::AudioGroupDatabase>&& data, const NameUndoRegistry& registry);
|
||||||
|
std::unique_ptr<amuse::AudioGroupDatabase> _delNode(GroupNode* node, NameUndoRegistry& registry);
|
||||||
|
GroupNode* newSubproject(const QString& name);
|
||||||
|
template <class NT, class T>
|
||||||
|
void _addGroupNode(NT* node, GroupNode* parent, const NameUndoRegistry& registry, T& container);
|
||||||
|
template <class NT, class T>
|
||||||
|
void _delGroupNode(NT* node, GroupNode* parent, NameUndoRegistry& registry, T& container);
|
||||||
|
void _addNode(SoundGroupNode* node, GroupNode* parent, const NameUndoRegistry& registry);
|
||||||
|
void _delNode(SoundGroupNode* node, GroupNode* parent, NameUndoRegistry& registry);
|
||||||
|
SoundGroupNode* newSoundGroup(GroupNode* group, const QString& name);
|
||||||
|
void _addNode(SongGroupNode* node, GroupNode* parent, const NameUndoRegistry& registry);
|
||||||
|
void _delNode(SongGroupNode* node, GroupNode* parent, NameUndoRegistry& registry);
|
||||||
|
SongGroupNode* newSongGroup(GroupNode* group, const QString& name);
|
||||||
|
template <class NT, class T>
|
||||||
|
void _addPoolNode(NT* node, GroupNode* parent, const NameUndoRegistry& registry, T& container);
|
||||||
|
template <class NT, class T>
|
||||||
|
void _delPoolNode(NT* node, GroupNode* parent, NameUndoRegistry& registry, T& container);
|
||||||
|
void _addNode(SoundMacroNode* node, GroupNode* parent, const NameUndoRegistry& registry);
|
||||||
|
void _delNode(SoundMacroNode* node, GroupNode* parent, NameUndoRegistry& registry);
|
||||||
|
SoundMacroNode* newSoundMacro(GroupNode* group, const QString& name,
|
||||||
|
const SoundMacroTemplateEntry* templ = nullptr);
|
||||||
|
void _addNode(ADSRNode* node, GroupNode* parent, const NameUndoRegistry& registry);
|
||||||
|
void _delNode(ADSRNode* node, GroupNode* parent, NameUndoRegistry& registry);
|
||||||
|
ADSRNode* newADSR(GroupNode* group, const QString& name);
|
||||||
|
void _addNode(CurveNode* node, GroupNode* parent, const NameUndoRegistry& registry);
|
||||||
|
void _delNode(CurveNode* node, GroupNode* parent, NameUndoRegistry& registry);
|
||||||
|
CurveNode* newCurve(GroupNode* group, const QString& name);
|
||||||
|
void _addNode(KeymapNode* node, GroupNode* parent, const NameUndoRegistry& registry);
|
||||||
|
void _delNode(KeymapNode* node, GroupNode* parent, NameUndoRegistry& registry);
|
||||||
|
KeymapNode* newKeymap(GroupNode* group, const QString& name);
|
||||||
|
void _addNode(LayersNode* node, GroupNode* parent, const NameUndoRegistry& registry);
|
||||||
|
void _delNode(LayersNode* node, GroupNode* parent, NameUndoRegistry& registry);
|
||||||
|
LayersNode* newLayers(GroupNode* group, const QString& name);
|
||||||
|
void _renameNode(INode* node, const QString& name);
|
||||||
|
|
||||||
|
template <class NT>
|
||||||
|
EditorUndoCommand* readMimeYAML(athena::io::YAMLDocReader& r, const QString& name, GroupNode* gn);
|
||||||
|
template <class NT>
|
||||||
|
void loadMimeData(const QMimeData* data, const QString& mimeType, GroupNode* gn);
|
||||||
|
|
||||||
|
QStringList mimeTypes() const;
|
||||||
|
QMimeData* mimeData(const QModelIndexList& indexes) const;
|
||||||
|
bool dropMimeData(const QMimeData* data, Qt::DropAction action, int row, int column, const QModelIndex &parent);
|
||||||
|
|
||||||
|
void cut(const QModelIndex& index);
|
||||||
|
void copy(const QModelIndex& index);
|
||||||
|
void paste(const QModelIndex& index);
|
||||||
|
QModelIndex duplicate(const QModelIndex& index);
|
||||||
|
void del(const QModelIndex& index);
|
||||||
|
|
||||||
|
const QDir& dir() const { return m_dir; }
|
||||||
|
QString path() const { return m_dir.path(); }
|
||||||
|
OutlineFilterProxyModel* getOutlineProxy() { return &m_outlineProxy; }
|
||||||
|
NullItemProxyModel* getNullProxy() { return &m_nullProxy; }
|
||||||
|
PageObjectProxyModel* getPageObjectProxy() { return &m_pageObjectProxy; }
|
||||||
|
|
||||||
|
GroupNode* getGroupOfSfx(amuse::SFXId id) const;
|
||||||
|
QString getMIDIPathOfSong(amuse::SongId id) const;
|
||||||
|
void setMIDIPathOfSong(amuse::SongId id, const QString& path);
|
||||||
|
std::pair<amuse::SongId, std::string> bootstrapSongId();
|
||||||
|
void allocateSongId(amuse::SongId id, std::string_view name);
|
||||||
|
void deallocateSongId(amuse::SongId oldId);
|
||||||
|
amuse::SongId exchangeSongId(amuse::SongId oldId, std::string_view newName);
|
||||||
|
|
||||||
|
void setIdDatabases(INode* context) const;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
#endif //AMUSE_PROJECT_MODEL_HPP
|
||||||
899
Editor/SampleEditor.cpp
Normal file
@@ -0,0 +1,899 @@
|
|||||||
|
#include "SampleEditor.hpp"
|
||||||
|
#include "MainWindow.hpp"
|
||||||
|
#include "amuse/DSPCodec.hpp"
|
||||||
|
#include <QPainter>
|
||||||
|
#include <QPaintEvent>
|
||||||
|
#include <QSpinBox>
|
||||||
|
#include <QScrollBar>
|
||||||
|
#include <QCheckBox>
|
||||||
|
|
||||||
|
SampleEditor* SampleView::getEditor() const
|
||||||
|
{
|
||||||
|
return qobject_cast<SampleEditor*>(parentWidget()->parentWidget()->parentWidget());
|
||||||
|
}
|
||||||
|
|
||||||
|
void SampleView::seekToSample(qreal sample)
|
||||||
|
{
|
||||||
|
sample = std::min(sample, qreal(m_sample->getNumSamples()));
|
||||||
|
|
||||||
|
if (m_sample->isFormatDSP())
|
||||||
|
{
|
||||||
|
if (sample < m_curSamplePos)
|
||||||
|
{
|
||||||
|
m_prev1 = m_prev2 = 0;
|
||||||
|
m_curSamplePos = 0.0;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t startBlock = uint32_t(m_curSamplePos) / 14;
|
||||||
|
uint32_t startRem = uint32_t(m_curSamplePos) % 14;
|
||||||
|
uint32_t endBlock = uint32_t(sample) / 14;
|
||||||
|
uint32_t endRem = uint32_t(sample) % 14;
|
||||||
|
|
||||||
|
if (startRem)
|
||||||
|
{
|
||||||
|
uint32_t end = 14;
|
||||||
|
if (startBlock == endBlock)
|
||||||
|
{
|
||||||
|
end = endRem;
|
||||||
|
endRem = 0;
|
||||||
|
}
|
||||||
|
DSPDecompressFrameRangedStateOnly(m_sampleData + 8 * startBlock, m_sample->m_ADPCMParms.dsp.m_coefs,
|
||||||
|
&m_prev1, &m_prev2, startRem, end);
|
||||||
|
if (end == 14)
|
||||||
|
++startBlock;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (uint32_t b = startBlock; b < endBlock; ++b)
|
||||||
|
{
|
||||||
|
DSPDecompressFrameStateOnly(m_sampleData + 8 * b, m_sample->m_ADPCMParms.dsp.m_coefs,
|
||||||
|
&m_prev1, &m_prev2, 14);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (endRem)
|
||||||
|
{
|
||||||
|
DSPDecompressFrameStateOnly(m_sampleData + 8 * endBlock, m_sample->m_ADPCMParms.dsp.m_coefs,
|
||||||
|
&m_prev1, &m_prev2, endRem);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
m_curSamplePos = sample;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::pair<std::pair<qreal, qreal>, std::pair<qreal, qreal>> SampleView::iterateSampleInterval(qreal interval)
|
||||||
|
{
|
||||||
|
std::pair<std::pair<qreal, qreal>, std::pair<qreal, qreal>> ret = {{0.0, 1.0}, {0.0, -1.0}}; // min,max avg,peak
|
||||||
|
qreal avg = 0.0;
|
||||||
|
qreal div = 0.0;
|
||||||
|
qreal endSample = std::min(m_curSamplePos + interval, qreal(m_sample->getNumSamples()));
|
||||||
|
|
||||||
|
auto accumulate = [&ret, &avg, &div](int16_t sample)
|
||||||
|
{
|
||||||
|
qreal sampleF = sample / 32768.0;
|
||||||
|
avg += sampleF;
|
||||||
|
div += 1.0;
|
||||||
|
ret.first.second = std::min(ret.first.second, sampleF);
|
||||||
|
ret.second.second = std::max(ret.second.second, sampleF);
|
||||||
|
};
|
||||||
|
|
||||||
|
if (m_sample->isFormatDSP())
|
||||||
|
{
|
||||||
|
uint32_t startBlock = uint32_t(m_curSamplePos) / 14;
|
||||||
|
uint32_t startRem = uint32_t(m_curSamplePos) % 14;
|
||||||
|
uint32_t endBlock = uint32_t(endSample) / 14;
|
||||||
|
uint32_t endRem = uint32_t(endSample) % 14;
|
||||||
|
|
||||||
|
int16_t sampleBlock[14];
|
||||||
|
|
||||||
|
if (startRem)
|
||||||
|
{
|
||||||
|
uint32_t end = 14;
|
||||||
|
if (startBlock == endBlock)
|
||||||
|
{
|
||||||
|
end = endRem;
|
||||||
|
endRem = 0;
|
||||||
|
}
|
||||||
|
DSPDecompressFrameRanged(sampleBlock, m_sampleData + 8 * startBlock, m_sample->m_ADPCMParms.dsp.m_coefs,
|
||||||
|
&m_prev1, &m_prev2, startRem, end);
|
||||||
|
for (int s = 0; s < end - startRem; ++s)
|
||||||
|
accumulate(sampleBlock[s]);
|
||||||
|
if (end == 14)
|
||||||
|
++startBlock;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (uint32_t b = startBlock; b < endBlock; ++b)
|
||||||
|
{
|
||||||
|
DSPDecompressFrame(sampleBlock, m_sampleData + 8 * b, m_sample->m_ADPCMParms.dsp.m_coefs,
|
||||||
|
&m_prev1, &m_prev2, 14);
|
||||||
|
for (int s = 0; s < 14; ++s)
|
||||||
|
accumulate(sampleBlock[s]);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (endRem)
|
||||||
|
{
|
||||||
|
DSPDecompressFrame(sampleBlock, m_sampleData + 8 * endBlock, m_sample->m_ADPCMParms.dsp.m_coefs,
|
||||||
|
&m_prev1, &m_prev2, endRem);
|
||||||
|
for (int s = 0; s < endRem; ++s)
|
||||||
|
accumulate(sampleBlock[s]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (m_sample->getSampleFormat() == amuse::SampleFormat::PCM_PC)
|
||||||
|
{
|
||||||
|
for (uint32_t s = uint32_t(m_curSamplePos); s < uint32_t(endSample); ++s)
|
||||||
|
accumulate(reinterpret_cast<const int16_t*>(m_sampleData)[s]);
|
||||||
|
}
|
||||||
|
|
||||||
|
m_curSamplePos = endSample;
|
||||||
|
|
||||||
|
if (div == 0.0)
|
||||||
|
return {};
|
||||||
|
|
||||||
|
avg /= div;
|
||||||
|
|
||||||
|
if (avg > 0.0)
|
||||||
|
{
|
||||||
|
ret.first.first = ret.first.second;
|
||||||
|
ret.second.first = avg;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
ret.first.first = avg;
|
||||||
|
ret.second.first = ret.second.second;
|
||||||
|
}
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
void SampleView::paintEvent(QPaintEvent* ev)
|
||||||
|
{
|
||||||
|
QPainter painter(this);
|
||||||
|
|
||||||
|
constexpr int rulerHeight = 28;
|
||||||
|
int sampleHeight = height() - rulerHeight;
|
||||||
|
|
||||||
|
qreal deviceRatio = devicePixelRatioF();
|
||||||
|
qreal rectStart = ev->rect().x();
|
||||||
|
qreal deviceWidth = ev->rect().width() * deviceRatio;
|
||||||
|
qreal increment = 1.0 / deviceRatio;
|
||||||
|
qreal deviceSamplesPerPx = m_samplesPerPx / deviceRatio;
|
||||||
|
qreal startSample = rectStart * m_samplesPerPx;
|
||||||
|
qreal startSampleRem = std::fmod(startSample, deviceSamplesPerPx);
|
||||||
|
if (startSampleRem > DBL_EPSILON)
|
||||||
|
{
|
||||||
|
startSample -= startSampleRem;
|
||||||
|
deviceWidth += startSampleRem;
|
||||||
|
rectStart = startSample / m_samplesPerPx;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (m_sample)
|
||||||
|
{
|
||||||
|
QPen peakPen(QColor(255, 147, 41), increment);
|
||||||
|
QPen avgPen(QColor(254, 177, 68), increment);
|
||||||
|
|
||||||
|
qreal scale = -sampleHeight / 2.0;
|
||||||
|
qreal trans = sampleHeight / 2.0;
|
||||||
|
|
||||||
|
std::pair<std::pair<qreal, qreal>, std::pair<qreal, qreal>> lastAvgPeak;
|
||||||
|
if (startSample >= deviceSamplesPerPx)
|
||||||
|
{
|
||||||
|
seekToSample(startSample - deviceSamplesPerPx);
|
||||||
|
lastAvgPeak = iterateSampleInterval(deviceSamplesPerPx);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
seekToSample(startSample);
|
||||||
|
lastAvgPeak = std::pair<std::pair<qreal, qreal>, std::pair<qreal, qreal>>{};
|
||||||
|
}
|
||||||
|
|
||||||
|
std::pair<std::pair<qreal, qreal>, std::pair<qreal, qreal>> avgPeak;
|
||||||
|
for (qreal i = 0.0; i < deviceWidth; i += increment)
|
||||||
|
{
|
||||||
|
if (m_curSamplePos + deviceSamplesPerPx > m_sample->getNumSamples())
|
||||||
|
break;
|
||||||
|
if (i == 0.0 || std::floor(m_curSamplePos) != std::floor(m_curSamplePos + deviceSamplesPerPx))
|
||||||
|
avgPeak = iterateSampleInterval(deviceSamplesPerPx);
|
||||||
|
else
|
||||||
|
m_curSamplePos += deviceSamplesPerPx;
|
||||||
|
std::pair<std::pair<qreal, qreal>, std::pair<qreal, qreal>> drawAvgPeak = avgPeak;
|
||||||
|
if (lastAvgPeak.first.first > avgPeak.second.first)
|
||||||
|
drawAvgPeak.second.first = lastAvgPeak.first.first;
|
||||||
|
else if (lastAvgPeak.second.first < avgPeak.first.first)
|
||||||
|
drawAvgPeak.first.first = lastAvgPeak.second.first;
|
||||||
|
painter.setPen(peakPen);
|
||||||
|
painter.drawLine(QPointF(rectStart + i, drawAvgPeak.first.second * scale + trans),
|
||||||
|
QPointF(rectStart + i, drawAvgPeak.second.second * scale + trans));
|
||||||
|
painter.setPen(avgPen);
|
||||||
|
painter.drawLine(QPointF(rectStart + i, drawAvgPeak.first.first * scale + trans),
|
||||||
|
QPointF(rectStart + i, drawAvgPeak.second.first * scale + trans));
|
||||||
|
lastAvgPeak = avgPeak;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
painter.setBrush(palette().brush(QPalette::Base));
|
||||||
|
painter.setPen(Qt::NoPen);
|
||||||
|
painter.drawRect(QRect(ev->rect().x(), sampleHeight, ev->rect().width(), rulerHeight));
|
||||||
|
|
||||||
|
constexpr qreal minNumSpacing = 40.0;
|
||||||
|
|
||||||
|
qreal binaryDiv = 1.0;
|
||||||
|
while (m_samplesPerPx * minNumSpacing > binaryDiv)
|
||||||
|
binaryDiv *= 2.0;
|
||||||
|
|
||||||
|
qreal numSpacing = binaryDiv / m_samplesPerPx;
|
||||||
|
qreal tickSpacing = numSpacing / 5;
|
||||||
|
|
||||||
|
int startX = std::max(0, int(ev->rect().x() - numSpacing));
|
||||||
|
int lastNumDiv = int(startX / numSpacing);
|
||||||
|
int lastTickDiv = int(startX / tickSpacing);
|
||||||
|
|
||||||
|
qreal samplePos = startX * m_samplesPerPx;
|
||||||
|
painter.setFont(m_rulerFont);
|
||||||
|
painter.setPen(QPen(QColor(127, 127, 127), increment));
|
||||||
|
for (int i = startX; i < ev->rect().x() + ev->rect().width() + numSpacing; ++i)
|
||||||
|
{
|
||||||
|
int thisNumDiv = int(i / numSpacing);
|
||||||
|
int thisTickDiv = int(i / tickSpacing);
|
||||||
|
|
||||||
|
if (thisNumDiv != lastNumDiv)
|
||||||
|
{
|
||||||
|
painter.drawLine(i, sampleHeight + 1, i, sampleHeight + 8);
|
||||||
|
lastNumDiv = thisNumDiv;
|
||||||
|
lastTickDiv = thisTickDiv;
|
||||||
|
|
||||||
|
painter.drawText(QRectF(i - numSpacing / 2.0, sampleHeight + 11.0, numSpacing, 12.0),
|
||||||
|
QString::number(int(samplePos)), QTextOption(Qt::AlignCenter));
|
||||||
|
}
|
||||||
|
else if (thisTickDiv != lastTickDiv)
|
||||||
|
{
|
||||||
|
painter.drawLine(i, sampleHeight + 1, i, sampleHeight + 5);
|
||||||
|
lastTickDiv = thisTickDiv;
|
||||||
|
}
|
||||||
|
|
||||||
|
samplePos += m_samplesPerPx;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (m_sample)
|
||||||
|
{
|
||||||
|
if (m_sample->isLooped())
|
||||||
|
{
|
||||||
|
int loopStart = m_sample->m_loopStartSample;
|
||||||
|
int loopEnd = loopStart + m_sample->m_loopLengthSamples - 1;
|
||||||
|
QPointF points[4];
|
||||||
|
|
||||||
|
painter.setPen(QPen(Qt::green, increment));
|
||||||
|
painter.setBrush(Qt::green);
|
||||||
|
qreal startPos = loopStart / m_samplesPerPx;
|
||||||
|
painter.drawLine(QPointF(startPos, 0.0), QPointF(startPos, height()));
|
||||||
|
points[0] = QPointF(startPos, height() - 6.0);
|
||||||
|
points[1] = QPointF(startPos - 6.0, height());
|
||||||
|
points[2] = QPointF(startPos + 6.0, height());
|
||||||
|
points[3] = QPointF(startPos, height() - 6.0);
|
||||||
|
painter.drawPolygon(points, 4);
|
||||||
|
|
||||||
|
painter.setPen(QPen(Qt::red, increment));
|
||||||
|
painter.setBrush(Qt::red);
|
||||||
|
qreal endPos = loopEnd / m_samplesPerPx;
|
||||||
|
painter.drawLine(QPointF(endPos, 0.0), QPointF(endPos, height()));
|
||||||
|
points[0] = QPointF(endPos, height() - 6.0);
|
||||||
|
points[1] = QPointF(endPos - 6.0, height());
|
||||||
|
points[2] = QPointF(endPos + 6.0, height());
|
||||||
|
points[3] = QPointF(endPos, height() - 6.0);
|
||||||
|
painter.drawPolygon(points, 4);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (m_displaySamplePos >= 0)
|
||||||
|
{
|
||||||
|
painter.setPen(QPen(Qt::white, increment));
|
||||||
|
qreal pos = m_displaySamplePos / m_samplesPerPx;
|
||||||
|
painter.drawLine(QPointF(pos, 0.0), QPointF(pos, height()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void SampleView::calculateSamplesPerPx()
|
||||||
|
{
|
||||||
|
m_samplesPerPx = (1.0 - m_zoomFactor) * m_baseSamplesPerPx + m_zoomFactor * 1.0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void SampleView::resetZoom()
|
||||||
|
{
|
||||||
|
if (QScrollArea* scroll = qobject_cast<QScrollArea*>(parentWidget()->parentWidget()))
|
||||||
|
{
|
||||||
|
m_baseSamplesPerPx = m_sample->getNumSamples() / qreal(scroll->width() - 4);
|
||||||
|
calculateSamplesPerPx();
|
||||||
|
setMinimumWidth(int(m_sample->getNumSamples() / m_samplesPerPx) + 1);
|
||||||
|
update();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void SampleView::setZoom(int zVal)
|
||||||
|
{
|
||||||
|
m_zoomFactor = zVal / 99.0;
|
||||||
|
calculateSamplesPerPx();
|
||||||
|
setMinimumWidth(int(m_sample->getNumSamples() / m_samplesPerPx) + 1);
|
||||||
|
update();
|
||||||
|
}
|
||||||
|
|
||||||
|
void SampleView::showEvent(QShowEvent* ev)
|
||||||
|
{
|
||||||
|
setZoom(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
void SampleView::mousePressEvent(QMouseEvent* ev)
|
||||||
|
{
|
||||||
|
if (m_sample && m_sample->isLooped())
|
||||||
|
{
|
||||||
|
int loopStart = m_sample->m_loopStartSample;
|
||||||
|
int startPos = int(loopStart / m_samplesPerPx);
|
||||||
|
int startDelta = std::abs(startPos - ev->pos().x());
|
||||||
|
bool startPass = startDelta < 20;
|
||||||
|
|
||||||
|
int loopEnd = loopStart + m_sample->m_loopLengthSamples - 1;
|
||||||
|
int endPos = int(loopEnd / m_samplesPerPx);
|
||||||
|
int endDelta = std::abs(endPos - ev->pos().x());
|
||||||
|
bool endPass = endDelta < 20;
|
||||||
|
|
||||||
|
if (startPass && endPass)
|
||||||
|
{
|
||||||
|
if (startDelta == endDelta)
|
||||||
|
{
|
||||||
|
if (ev->pos().x() < startPos)
|
||||||
|
m_dragState = DragState::Start;
|
||||||
|
else
|
||||||
|
m_dragState = DragState::End;
|
||||||
|
}
|
||||||
|
else if (startDelta < endDelta)
|
||||||
|
m_dragState = DragState::Start;
|
||||||
|
else
|
||||||
|
m_dragState = DragState::End;
|
||||||
|
}
|
||||||
|
else if (startPass)
|
||||||
|
m_dragState = DragState::Start;
|
||||||
|
else if (endPass)
|
||||||
|
m_dragState = DragState::End;
|
||||||
|
|
||||||
|
getEditor()->m_controls->setFileWrite(m_dragState == DragState::None);
|
||||||
|
|
||||||
|
mouseMoveEvent(ev);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void SampleView::mouseReleaseEvent(QMouseEvent* ev)
|
||||||
|
{
|
||||||
|
m_dragState = DragState::None;
|
||||||
|
getEditor()->m_controls->setFileWrite(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
void SampleView::mouseMoveEvent(QMouseEvent* ev)
|
||||||
|
{
|
||||||
|
if (m_dragState == DragState::Start)
|
||||||
|
getEditor()->m_controls->setLoopStartSample(int(ev->pos().x() * m_samplesPerPx));
|
||||||
|
else if (m_dragState == DragState::End)
|
||||||
|
getEditor()->m_controls->setLoopEndSample(int(ev->pos().x() * m_samplesPerPx));
|
||||||
|
}
|
||||||
|
|
||||||
|
void SampleView::wheelEvent(QWheelEvent* ev)
|
||||||
|
{
|
||||||
|
if (QScrollArea* scroll = qobject_cast<QScrollArea*>(parentWidget()->parentWidget()))
|
||||||
|
{
|
||||||
|
/* Send wheel event directly to the scroll bar */
|
||||||
|
QApplication::sendEvent(scroll->horizontalScrollBar(), ev);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool SampleView::loadData(ProjectModel::SampleNode* node)
|
||||||
|
{
|
||||||
|
bool reset = m_node.get() != node;
|
||||||
|
m_node = node;
|
||||||
|
|
||||||
|
ProjectModel::GroupNode* group = g_MainWindow->projectModel()->getGroupNode(m_node.get());
|
||||||
|
std::tie(m_sample, m_sampleData) = group->getAudioGroup()->getSampleData(m_node->id(), m_node->m_obj.get());
|
||||||
|
if (reset)
|
||||||
|
resetZoom();
|
||||||
|
|
||||||
|
m_playbackMacro = amuse::MakeObj<amuse::SoundMacro>();
|
||||||
|
amuse::SoundMacro::CmdStartSample* startSample =
|
||||||
|
static_cast<amuse::SoundMacro::CmdStartSample*>(
|
||||||
|
m_playbackMacro->insertNewCmd(0, amuse::SoundMacro::CmdOp::StartSample));
|
||||||
|
startSample->sample.id = m_node->id();
|
||||||
|
m_playbackMacro->insertNewCmd(1, amuse::SoundMacro::CmdOp::End);
|
||||||
|
|
||||||
|
update();
|
||||||
|
|
||||||
|
return reset;
|
||||||
|
}
|
||||||
|
|
||||||
|
void SampleView::unloadData()
|
||||||
|
{
|
||||||
|
m_node.reset();
|
||||||
|
m_sample.reset();
|
||||||
|
m_playbackMacro.reset();
|
||||||
|
update();
|
||||||
|
}
|
||||||
|
|
||||||
|
ProjectModel::INode* SampleView::currentNode() const
|
||||||
|
{
|
||||||
|
return m_node.get();
|
||||||
|
}
|
||||||
|
|
||||||
|
amuse::SampleEntryData* SampleView::entryData() const
|
||||||
|
{
|
||||||
|
return m_sample.get();
|
||||||
|
}
|
||||||
|
|
||||||
|
const amuse::SoundMacro* SampleView::soundMacro() const
|
||||||
|
{
|
||||||
|
return m_playbackMacro.get();
|
||||||
|
}
|
||||||
|
|
||||||
|
void SampleView::setSamplePos(int pos)
|
||||||
|
{
|
||||||
|
if (pos != m_displaySamplePos)
|
||||||
|
{
|
||||||
|
if (pos >= 0)
|
||||||
|
{
|
||||||
|
int lastPos = m_displaySamplePos;
|
||||||
|
m_displaySamplePos = pos;
|
||||||
|
updateSampleRange(lastPos, pos);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
m_displaySamplePos = pos;
|
||||||
|
update();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void SampleView::updateSampleRange(int oldSamp, int newSamp)
|
||||||
|
{
|
||||||
|
qreal lastPos = oldSamp / m_samplesPerPx;
|
||||||
|
qreal newPos = newSamp / m_samplesPerPx;
|
||||||
|
update(int(std::min(lastPos, newPos)) - 10, 0,
|
||||||
|
int(std::fabs(newPos - lastPos)) + 20, height());
|
||||||
|
}
|
||||||
|
|
||||||
|
SampleView::SampleView(QWidget* parent)
|
||||||
|
: QWidget(parent)
|
||||||
|
{
|
||||||
|
setSizePolicy(QSizePolicy::Minimum, QSizePolicy::Preferred);
|
||||||
|
m_rulerFont.setPointSize(8);
|
||||||
|
}
|
||||||
|
|
||||||
|
void SampleControls::zoomSliderChanged(int val)
|
||||||
|
{
|
||||||
|
SampleEditor* editor = qobject_cast<SampleEditor*>(parentWidget());
|
||||||
|
editor->m_sampleView->setZoom(val);
|
||||||
|
}
|
||||||
|
|
||||||
|
class SampLoopUndoCommand : public EditorUndoCommand
|
||||||
|
{
|
||||||
|
uint32_t m_redoStartVal, m_redoEndVal, m_undoStartVal, m_undoEndVal;
|
||||||
|
int m_fieldIdx;
|
||||||
|
bool m_undid = false;
|
||||||
|
public:
|
||||||
|
SampLoopUndoCommand(uint32_t redoStart, uint32_t redoEnd, const QString& fieldName,
|
||||||
|
int fieldIdx, amuse::ObjToken<ProjectModel::SampleNode> node)
|
||||||
|
: EditorUndoCommand(node.get(), SampleControls::tr("Change %1").arg(fieldName)),
|
||||||
|
m_redoStartVal(redoStart), m_redoEndVal(redoEnd), m_fieldIdx(fieldIdx) {}
|
||||||
|
void undo()
|
||||||
|
{
|
||||||
|
m_undid = true;
|
||||||
|
amuse::SampleEntryData* data = m_node.cast<ProjectModel::SampleNode>()->m_obj->m_data.get();
|
||||||
|
data->setLoopStartSample(m_undoStartVal);
|
||||||
|
data->setLoopEndSample(m_undoEndVal);
|
||||||
|
EditorUndoCommand::undo();
|
||||||
|
if (SampleEditor* e = static_cast<SampleEditor*>(g_MainWindow->getEditorWidget()))
|
||||||
|
e->m_controls->doFileWrite();
|
||||||
|
}
|
||||||
|
void redo()
|
||||||
|
{
|
||||||
|
amuse::SampleEntryData* data = m_node.cast<ProjectModel::SampleNode>()->m_obj->m_data.get();
|
||||||
|
m_undoStartVal = data->getLoopStartSample();
|
||||||
|
m_undoEndVal = data->getLoopEndSample();
|
||||||
|
data->setLoopStartSample(m_redoStartVal);
|
||||||
|
data->setLoopEndSample(m_redoEndVal);
|
||||||
|
if (m_undid)
|
||||||
|
{
|
||||||
|
EditorUndoCommand::redo();
|
||||||
|
if (SampleEditor* e = static_cast<SampleEditor*>(g_MainWindow->getEditorWidget()))
|
||||||
|
e->m_controls->doFileWrite();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
bool mergeWith(const QUndoCommand* other)
|
||||||
|
{
|
||||||
|
if (other->id() == id() && static_cast<const SampLoopUndoCommand*>(other)->m_fieldIdx == m_fieldIdx)
|
||||||
|
{
|
||||||
|
m_redoStartVal = static_cast<const SampLoopUndoCommand*>(other)->m_redoStartVal;
|
||||||
|
m_redoEndVal = static_cast<const SampLoopUndoCommand*>(other)->m_redoEndVal;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
int id() const { return int(Id::SampLoop); }
|
||||||
|
};
|
||||||
|
|
||||||
|
void SampleControls::loopStateChanged(int state)
|
||||||
|
{
|
||||||
|
if (m_enableUpdate)
|
||||||
|
{
|
||||||
|
SampleEditor* editor = qobject_cast<SampleEditor*>(parentWidget());
|
||||||
|
amuse::SampleEntryData* data = editor->m_sampleView->entryData();
|
||||||
|
if (state == Qt::Checked)
|
||||||
|
{
|
||||||
|
g_MainWindow->pushUndoCommand(new SampLoopUndoCommand(atUint32(m_loopStart->value()),
|
||||||
|
uint32_t(m_loopEnd->value()), tr("Loop"), 0, editor->m_sampleView->m_node));
|
||||||
|
m_loopStart->setEnabled(true);
|
||||||
|
m_loopEnd->setEnabled(true);
|
||||||
|
if (m_loopStart->value() == 0 && m_loopEnd->value() == 0)
|
||||||
|
{
|
||||||
|
m_enableUpdate = false;
|
||||||
|
m_loopEnd->setValue(data->getNumSamples() - 1);
|
||||||
|
m_loopStart->setMaximum(m_loopEnd->value());
|
||||||
|
m_enableUpdate = true;
|
||||||
|
}
|
||||||
|
data->m_loopStartSample = atUint32(m_loopStart->value());
|
||||||
|
data->m_loopLengthSamples = m_loopEnd->value() + 1 - data->m_loopStartSample;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
g_MainWindow->pushUndoCommand(new SampLoopUndoCommand(0, 0, tr("Loop"), 0, editor->m_sampleView->m_node));
|
||||||
|
m_loopStart->setEnabled(false);
|
||||||
|
m_loopEnd->setEnabled(false);
|
||||||
|
data->m_loopStartSample = 0;
|
||||||
|
data->m_loopLengthSamples = 0;
|
||||||
|
}
|
||||||
|
editor->m_sampleView->update();
|
||||||
|
doFileWrite();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void SampleControls::startValueChanged(int val)
|
||||||
|
{
|
||||||
|
if (m_enableUpdate)
|
||||||
|
{
|
||||||
|
SampleEditor* editor = qobject_cast<SampleEditor*>(parentWidget());
|
||||||
|
amuse::SampleEntryData* data = editor->m_sampleView->entryData();
|
||||||
|
|
||||||
|
int oldPos = data->getLoopStartSample();
|
||||||
|
g_MainWindow->pushUndoCommand(new SampLoopUndoCommand(atUint32(val), data->getLoopEndSample(), tr("Loop Start"),
|
||||||
|
1, editor->m_sampleView->m_node));
|
||||||
|
|
||||||
|
data->setLoopStartSample(atUint32(val));
|
||||||
|
m_loopEnd->setMinimum(val);
|
||||||
|
|
||||||
|
editor->m_sampleView->updateSampleRange(oldPos, val);
|
||||||
|
doFileWrite();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void SampleControls::endValueChanged(int val)
|
||||||
|
{
|
||||||
|
if (m_enableUpdate)
|
||||||
|
{
|
||||||
|
SampleEditor* editor = qobject_cast<SampleEditor*>(parentWidget());
|
||||||
|
amuse::SampleEntryData* data = editor->m_sampleView->entryData();
|
||||||
|
|
||||||
|
int oldPos = data->getLoopEndSample();
|
||||||
|
g_MainWindow->pushUndoCommand(new SampLoopUndoCommand(data->getLoopStartSample(), atUint32(val), tr("Loop End"),
|
||||||
|
2, editor->m_sampleView->m_node));
|
||||||
|
|
||||||
|
data->setLoopEndSample(atUint32(val));
|
||||||
|
m_loopStart->setMaximum(val);
|
||||||
|
|
||||||
|
editor->m_sampleView->updateSampleRange(oldPos, val);
|
||||||
|
doFileWrite();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class SampPitchUndoCommand : public EditorUndoCommand
|
||||||
|
{
|
||||||
|
uint8_t m_redoPitchVal, m_undoPitchVal;
|
||||||
|
bool m_undid = false;
|
||||||
|
public:
|
||||||
|
SampPitchUndoCommand(atUint8 redoPitch, amuse::ObjToken<ProjectModel::SampleNode> node)
|
||||||
|
: EditorUndoCommand(node.get(), SampleControls::tr("Change Base Pitch")),
|
||||||
|
m_redoPitchVal(redoPitch) {}
|
||||||
|
void undo()
|
||||||
|
{
|
||||||
|
m_undid = true;
|
||||||
|
amuse::SampleEntryData* data = m_node.cast<ProjectModel::SampleNode>()->m_obj->m_data.get();
|
||||||
|
data->m_pitch = m_undoPitchVal;
|
||||||
|
EditorUndoCommand::undo();
|
||||||
|
if (SampleEditor* e = static_cast<SampleEditor*>(g_MainWindow->getEditorWidget()))
|
||||||
|
e->m_controls->doFileWrite();
|
||||||
|
}
|
||||||
|
void redo()
|
||||||
|
{
|
||||||
|
amuse::SampleEntryData* data = m_node.cast<ProjectModel::SampleNode>()->m_obj->m_data.get();
|
||||||
|
m_undoPitchVal = data->m_pitch;
|
||||||
|
data->m_pitch = m_redoPitchVal;
|
||||||
|
if (m_undid)
|
||||||
|
{
|
||||||
|
EditorUndoCommand::redo();
|
||||||
|
if (SampleEditor* e = static_cast<SampleEditor*>(g_MainWindow->getEditorWidget()))
|
||||||
|
e->m_controls->doFileWrite();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
bool mergeWith(const QUndoCommand* other)
|
||||||
|
{
|
||||||
|
if (other->id() == id())
|
||||||
|
{
|
||||||
|
m_redoPitchVal = static_cast<const SampPitchUndoCommand*>(other)->m_redoPitchVal;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
int id() const { return int(Id::SampPitch); }
|
||||||
|
};
|
||||||
|
|
||||||
|
void SampleControls::pitchValueChanged(int val)
|
||||||
|
{
|
||||||
|
if (m_enableUpdate)
|
||||||
|
{
|
||||||
|
SampleEditor* editor = qobject_cast<SampleEditor*>(parentWidget());
|
||||||
|
amuse::SampleEntryData* data = editor->m_sampleView->entryData();
|
||||||
|
|
||||||
|
g_MainWindow->pushUndoCommand(new SampPitchUndoCommand(atUint8(val), editor->m_sampleView->m_node));
|
||||||
|
|
||||||
|
data->m_pitch = atUint8(val);
|
||||||
|
doFileWrite();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void SampleControls::makeWAVVersion()
|
||||||
|
{
|
||||||
|
SampleEditor* editor = qobject_cast<SampleEditor*>(parentWidget());
|
||||||
|
ProjectModel::SampleNode* node = static_cast<ProjectModel::SampleNode*>(editor->currentNode());
|
||||||
|
g_MainWindow->projectModel()->getGroupNode(node)->getAudioGroup()->
|
||||||
|
makeWAVVersion(node->id(), node->m_obj.get());
|
||||||
|
updateFileState();
|
||||||
|
}
|
||||||
|
|
||||||
|
void SampleControls::makeCompressedVersion()
|
||||||
|
{
|
||||||
|
SampleEditor* editor = qobject_cast<SampleEditor*>(parentWidget());
|
||||||
|
ProjectModel::SampleNode* node = static_cast<ProjectModel::SampleNode*>(editor->currentNode());
|
||||||
|
g_MainWindow->projectModel()->getGroupNode(node)->getAudioGroup()->
|
||||||
|
makeCompressedVersion(node->id(), node->m_obj.get());
|
||||||
|
updateFileState();
|
||||||
|
}
|
||||||
|
|
||||||
|
void SampleControls::showInBrowser()
|
||||||
|
{
|
||||||
|
ShowInGraphicalShell(this, m_path);
|
||||||
|
}
|
||||||
|
|
||||||
|
void SampleControls::updateFileState()
|
||||||
|
{
|
||||||
|
m_enableUpdate = false;
|
||||||
|
|
||||||
|
SampleEditor* editor = qobject_cast<SampleEditor*>(parentWidget());
|
||||||
|
ProjectModel::SampleNode* node = static_cast<ProjectModel::SampleNode*>(editor->currentNode());
|
||||||
|
|
||||||
|
amuse::SystemString path;
|
||||||
|
amuse::SampleFileState state =
|
||||||
|
g_MainWindow->projectModel()->getGroupNode(node)->getAudioGroup()->
|
||||||
|
getSampleFileState(node->id(), node->m_obj.get(), &path);
|
||||||
|
disconnect(m_makeOtherConn);
|
||||||
|
|
||||||
|
switch (state)
|
||||||
|
{
|
||||||
|
case amuse::SampleFileState::MemoryOnlyWAV:
|
||||||
|
case amuse::SampleFileState::CompressedNoWAV:
|
||||||
|
m_makeOtherVersion->setText(tr("Make WAV Version"));
|
||||||
|
m_makeOtherVersion->setDisabled(false);
|
||||||
|
m_makeOtherConn = connect(m_makeOtherVersion, SIGNAL(clicked(bool)), this, SLOT(makeWAVVersion()));
|
||||||
|
break;
|
||||||
|
case amuse::SampleFileState::MemoryOnlyCompressed:
|
||||||
|
case amuse::SampleFileState::WAVRecent:
|
||||||
|
case amuse::SampleFileState::WAVNoCompressed:
|
||||||
|
m_makeOtherVersion->setText(tr("Make Compressed Version"));
|
||||||
|
m_makeOtherVersion->setDisabled(false);
|
||||||
|
m_makeOtherConn = connect(m_makeOtherVersion, SIGNAL(clicked(bool)), this, SLOT(makeCompressedVersion()));
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
m_makeOtherVersion->setText(tr("Up To Date"));
|
||||||
|
m_makeOtherVersion->setDisabled(true);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
amuse::SampleEntryData* data = editor->m_sampleView->entryData();
|
||||||
|
m_loopCheck->setChecked(data->isLooped());
|
||||||
|
int loopStart = 0;
|
||||||
|
int loopEnd = 0;
|
||||||
|
int loopMax = data->getNumSamples() - 1;
|
||||||
|
if (data->isLooped())
|
||||||
|
{
|
||||||
|
loopStart = data->m_loopStartSample;
|
||||||
|
loopEnd = loopStart + data->m_loopLengthSamples - 1;
|
||||||
|
}
|
||||||
|
m_loopStart->setMaximum(loopEnd);
|
||||||
|
m_loopEnd->setMinimum(loopStart);
|
||||||
|
m_loopEnd->setMaximum(loopMax);
|
||||||
|
m_loopStart->setValue(loopStart);
|
||||||
|
m_loopEnd->setValue(loopEnd);
|
||||||
|
m_basePitch->setValue(data->m_pitch);
|
||||||
|
m_loopStart->setEnabled(data->isLooped());
|
||||||
|
m_loopEnd->setEnabled(data->isLooped());
|
||||||
|
|
||||||
|
if (!path.empty())
|
||||||
|
{
|
||||||
|
m_path = SysStringToQString(path);
|
||||||
|
m_showInBrowser->setDisabled(false);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
m_path = QString();
|
||||||
|
m_showInBrowser->setDisabled(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
m_enableUpdate = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void SampleControls::doFileWrite()
|
||||||
|
{
|
||||||
|
if (m_enableFileWrite)
|
||||||
|
{
|
||||||
|
SampleEditor* editor = qobject_cast<SampleEditor*>(parentWidget());
|
||||||
|
ProjectModel::SampleNode* node = static_cast<ProjectModel::SampleNode*>(editor->currentNode());
|
||||||
|
g_MainWindow->projectModel()->getGroupNode(node)->getAudioGroup()->
|
||||||
|
patchSampleMetadata(node->id(), node->m_obj.get());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void SampleControls::setFileWrite(bool w)
|
||||||
|
{
|
||||||
|
m_enableFileWrite = w;
|
||||||
|
doFileWrite();
|
||||||
|
}
|
||||||
|
|
||||||
|
void SampleControls::loadData(bool reset)
|
||||||
|
{
|
||||||
|
m_zoomSlider->setDisabled(false);
|
||||||
|
m_loopCheck->setDisabled(false);
|
||||||
|
m_loopStart->setDisabled(false);
|
||||||
|
m_loopEnd->setDisabled(false);
|
||||||
|
m_basePitch->setDisabled(false);
|
||||||
|
if (reset)
|
||||||
|
m_zoomSlider->setValue(0);
|
||||||
|
updateFileState();
|
||||||
|
}
|
||||||
|
|
||||||
|
void SampleControls::unloadData()
|
||||||
|
{
|
||||||
|
m_zoomSlider->setDisabled(true);
|
||||||
|
m_loopCheck->setDisabled(true);
|
||||||
|
m_loopStart->setDisabled(true);
|
||||||
|
m_loopEnd->setDisabled(true);
|
||||||
|
m_basePitch->setDisabled(true);
|
||||||
|
m_makeOtherVersion->setText(tr("Nothing Loaded"));
|
||||||
|
m_makeOtherVersion->setDisabled(true);
|
||||||
|
m_showInBrowser->setDisabled(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
SampleControls::SampleControls(QWidget* parent)
|
||||||
|
: QFrame(parent)
|
||||||
|
{
|
||||||
|
setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Fixed);
|
||||||
|
setFixedHeight(100);
|
||||||
|
setFrameShape(QFrame::StyledPanel);
|
||||||
|
setFrameShadow(QFrame::Sunken);
|
||||||
|
setBackgroundRole(QPalette::Base);
|
||||||
|
setAutoFillBackground(true);
|
||||||
|
|
||||||
|
QPalette palette = QWidget::palette();
|
||||||
|
palette.setColor(QPalette::Base, palette.color(QPalette::Background));
|
||||||
|
|
||||||
|
QHBoxLayout* mainLayout = new QHBoxLayout;
|
||||||
|
|
||||||
|
QGridLayout* leftLayout = new QGridLayout;
|
||||||
|
|
||||||
|
leftLayout->addWidget(new QLabel(tr("Zoom")), 0, 0);
|
||||||
|
m_zoomSlider = new QSlider(Qt::Horizontal);
|
||||||
|
m_zoomSlider->setDisabled(true);
|
||||||
|
m_zoomSlider->setRange(0, 99);
|
||||||
|
connect(m_zoomSlider, SIGNAL(valueChanged(int)), this, SLOT(zoomSliderChanged(int)));
|
||||||
|
leftLayout->addWidget(m_zoomSlider, 1, 0);
|
||||||
|
|
||||||
|
leftLayout->addWidget(new QLabel(tr("Loop")), 0, 1);
|
||||||
|
m_loopCheck = new QCheckBox;
|
||||||
|
m_loopCheck->setPalette(palette);
|
||||||
|
m_loopCheck->setDisabled(true);
|
||||||
|
connect(m_loopCheck, SIGNAL(stateChanged(int)), this, SLOT(loopStateChanged(int)));
|
||||||
|
leftLayout->addWidget(m_loopCheck, 1, 1);
|
||||||
|
|
||||||
|
leftLayout->addWidget(new QLabel(tr("Start")), 0, 2);
|
||||||
|
m_loopStart = new QSpinBox;
|
||||||
|
m_loopStart->setPalette(palette);
|
||||||
|
m_loopStart->setDisabled(true);
|
||||||
|
connect(m_loopStart, SIGNAL(valueChanged(int)), this, SLOT(startValueChanged(int)));
|
||||||
|
leftLayout->addWidget(m_loopStart, 1, 2);
|
||||||
|
|
||||||
|
leftLayout->addWidget(new QLabel(tr("End")), 0, 3);
|
||||||
|
m_loopEnd = new QSpinBox;
|
||||||
|
m_loopEnd->setPalette(palette);
|
||||||
|
m_loopEnd->setDisabled(true);
|
||||||
|
connect(m_loopEnd, SIGNAL(valueChanged(int)), this, SLOT(endValueChanged(int)));
|
||||||
|
leftLayout->addWidget(m_loopEnd, 1, 3);
|
||||||
|
|
||||||
|
leftLayout->addWidget(new QLabel(tr("Base Pitch")), 0, 4);
|
||||||
|
m_basePitch = new QSpinBox;
|
||||||
|
m_basePitch->setPalette(palette);
|
||||||
|
m_basePitch->setDisabled(true);
|
||||||
|
m_basePitch->setMinimum(0);
|
||||||
|
m_basePitch->setMaximum(127);
|
||||||
|
connect(m_basePitch, SIGNAL(valueChanged(int)), this, SLOT(pitchValueChanged(int)));
|
||||||
|
leftLayout->addWidget(m_basePitch, 1, 4);
|
||||||
|
|
||||||
|
leftLayout->setColumnMinimumWidth(0, 100);
|
||||||
|
leftLayout->setColumnMinimumWidth(1, 50);
|
||||||
|
leftLayout->setColumnMinimumWidth(2, 75);
|
||||||
|
leftLayout->setColumnMinimumWidth(3, 75);
|
||||||
|
leftLayout->setColumnMinimumWidth(4, 75);
|
||||||
|
leftLayout->setRowMinimumHeight(0, 22);
|
||||||
|
leftLayout->setRowMinimumHeight(1, 37);
|
||||||
|
leftLayout->setContentsMargins(10, 6, 0, 14);
|
||||||
|
|
||||||
|
QVBoxLayout* rightLayout = new QVBoxLayout;
|
||||||
|
|
||||||
|
m_makeOtherVersion = new QPushButton(tr("Nothing Loaded"));
|
||||||
|
m_makeOtherVersion->setMinimumWidth(250);
|
||||||
|
m_makeOtherVersion->setDisabled(true);
|
||||||
|
rightLayout->addWidget(m_makeOtherVersion);
|
||||||
|
m_showInBrowser = new QPushButton(ShowInGraphicalShellString());
|
||||||
|
m_showInBrowser->setMinimumWidth(250);
|
||||||
|
m_showInBrowser->setDisabled(true);
|
||||||
|
connect(m_showInBrowser, SIGNAL(clicked(bool)), this, SLOT(showInBrowser()));
|
||||||
|
rightLayout->addWidget(m_showInBrowser);
|
||||||
|
|
||||||
|
mainLayout->addLayout(leftLayout);
|
||||||
|
mainLayout->addStretch(1);
|
||||||
|
mainLayout->addLayout(rightLayout);
|
||||||
|
setLayout(mainLayout);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool SampleEditor::loadData(ProjectModel::SampleNode* node)
|
||||||
|
{
|
||||||
|
m_controls->loadData(m_sampleView->loadData(node));
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void SampleEditor::unloadData()
|
||||||
|
{
|
||||||
|
m_sampleView->unloadData();
|
||||||
|
m_controls->unloadData();
|
||||||
|
}
|
||||||
|
|
||||||
|
ProjectModel::INode* SampleEditor::currentNode() const
|
||||||
|
{
|
||||||
|
return m_sampleView->currentNode();
|
||||||
|
}
|
||||||
|
|
||||||
|
const amuse::SoundMacro* SampleEditor::soundMacro() const
|
||||||
|
{
|
||||||
|
return m_sampleView->soundMacro();
|
||||||
|
}
|
||||||
|
|
||||||
|
void SampleEditor::setSamplePos(int pos)
|
||||||
|
{
|
||||||
|
m_sampleView->setSamplePos(pos);
|
||||||
|
}
|
||||||
|
|
||||||
|
void SampleEditor::resizeEvent(QResizeEvent* ev)
|
||||||
|
{
|
||||||
|
m_sampleView->resetZoom();
|
||||||
|
}
|
||||||
|
|
||||||
|
SampleEditor::SampleEditor(QWidget* parent)
|
||||||
|
: EditorWidget(parent), m_scrollArea(new QScrollArea),
|
||||||
|
m_sampleView(new SampleView), m_controls(new SampleControls)
|
||||||
|
{
|
||||||
|
m_scrollArea->setWidget(m_sampleView);
|
||||||
|
m_scrollArea->setWidgetResizable(true);
|
||||||
|
|
||||||
|
QVBoxLayout* layout = new QVBoxLayout;
|
||||||
|
layout->setContentsMargins(QMargins());
|
||||||
|
layout->setSpacing(1);
|
||||||
|
layout->addWidget(m_scrollArea);
|
||||||
|
layout->addWidget(m_controls);
|
||||||
|
setLayout(layout);
|
||||||
|
}
|
||||||
116
Editor/SampleEditor.hpp
Normal file
@@ -0,0 +1,116 @@
|
|||||||
|
#ifndef AMUSE_SAMPLE_EDITOR_HPP
|
||||||
|
#define AMUSE_SAMPLE_EDITOR_HPP
|
||||||
|
|
||||||
|
#include "EditorWidget.hpp"
|
||||||
|
#include "ProjectModel.hpp"
|
||||||
|
#include <QScrollArea>
|
||||||
|
#include <QSlider>
|
||||||
|
#include <QCheckBox>
|
||||||
|
#include <QSpinBox>
|
||||||
|
|
||||||
|
class SampleEditor;
|
||||||
|
|
||||||
|
class SampleView : public QWidget
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
friend class SampleControls;
|
||||||
|
qreal m_baseSamplesPerPx = 100.0;
|
||||||
|
qreal m_samplesPerPx = 100.0;
|
||||||
|
qreal m_zoomFactor = 1.0;
|
||||||
|
amuse::ObjToken<ProjectModel::SampleNode> m_node;
|
||||||
|
amuse::ObjToken<amuse::SampleEntryData> m_sample;
|
||||||
|
amuse::ObjToken<amuse::SoundMacro> m_playbackMacro;
|
||||||
|
const unsigned char* m_sampleData = nullptr;
|
||||||
|
qreal m_curSamplePos = 0.0;
|
||||||
|
int16_t m_prev1 = 0;
|
||||||
|
int16_t m_prev2 = 0;
|
||||||
|
QFont m_rulerFont;
|
||||||
|
int m_displaySamplePos = -1;
|
||||||
|
enum class DragState
|
||||||
|
{
|
||||||
|
None,
|
||||||
|
Start,
|
||||||
|
End
|
||||||
|
};
|
||||||
|
DragState m_dragState = DragState::None;
|
||||||
|
void seekToSample(qreal sample);
|
||||||
|
std::pair<std::pair<qreal, qreal>, std::pair<qreal, qreal>> iterateSampleInterval(qreal interval);
|
||||||
|
void calculateSamplesPerPx();
|
||||||
|
SampleEditor* getEditor() const;
|
||||||
|
public:
|
||||||
|
explicit SampleView(QWidget* parent = Q_NULLPTR);
|
||||||
|
bool loadData(ProjectModel::SampleNode* node);
|
||||||
|
void unloadData();
|
||||||
|
ProjectModel::INode* currentNode() const;
|
||||||
|
amuse::SampleEntryData* entryData() const;
|
||||||
|
const amuse::SoundMacro* soundMacro() const;
|
||||||
|
void setSamplePos(int pos);
|
||||||
|
void updateSampleRange(int oldSamp, int newSamp);
|
||||||
|
|
||||||
|
void paintEvent(QPaintEvent* ev);
|
||||||
|
void resetZoom();
|
||||||
|
void setZoom(int zVal);
|
||||||
|
void showEvent(QShowEvent* ev);
|
||||||
|
void mousePressEvent(QMouseEvent* ev);
|
||||||
|
void mouseReleaseEvent(QMouseEvent* ev);
|
||||||
|
void mouseMoveEvent(QMouseEvent* ev);
|
||||||
|
void wheelEvent(QWheelEvent* ev);
|
||||||
|
};
|
||||||
|
|
||||||
|
class SampleControls : public QFrame
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
QString m_path;
|
||||||
|
QSlider* m_zoomSlider;
|
||||||
|
QCheckBox* m_loopCheck;
|
||||||
|
QSpinBox* m_loopStart;
|
||||||
|
QSpinBox* m_loopEnd;
|
||||||
|
QSpinBox* m_basePitch;
|
||||||
|
QPushButton* m_makeOtherVersion;
|
||||||
|
QMetaObject::Connection m_makeOtherConn;
|
||||||
|
QPushButton* m_showInBrowser;
|
||||||
|
bool m_enableUpdate = true;
|
||||||
|
bool m_enableFileWrite = true;
|
||||||
|
public:
|
||||||
|
explicit SampleControls(QWidget* parent = Q_NULLPTR);
|
||||||
|
void doFileWrite();
|
||||||
|
void setFileWrite(bool w);
|
||||||
|
void updateFileState();
|
||||||
|
void setLoopStartSample(int sample) { m_loopStart->setValue(sample); }
|
||||||
|
void setLoopEndSample(int sample) { m_loopEnd->setValue(sample); }
|
||||||
|
void loadData(bool reset);
|
||||||
|
void unloadData();
|
||||||
|
public slots:
|
||||||
|
void zoomSliderChanged(int val);
|
||||||
|
void loopStateChanged(int state);
|
||||||
|
void startValueChanged(int val);
|
||||||
|
void endValueChanged(int val);
|
||||||
|
void pitchValueChanged(int val);
|
||||||
|
void makeWAVVersion();
|
||||||
|
void makeCompressedVersion();
|
||||||
|
void showInBrowser();
|
||||||
|
};
|
||||||
|
|
||||||
|
class SampleEditor : public EditorWidget
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
friend class SampleView;
|
||||||
|
friend class SampleControls;
|
||||||
|
friend class SampLoopUndoCommand;
|
||||||
|
friend class SampPitchUndoCommand;
|
||||||
|
QScrollArea* m_scrollArea;
|
||||||
|
SampleView* m_sampleView;
|
||||||
|
SampleControls* m_controls;
|
||||||
|
public:
|
||||||
|
explicit SampleEditor(QWidget* parent = Q_NULLPTR);
|
||||||
|
bool loadData(ProjectModel::SampleNode* node);
|
||||||
|
void unloadData();
|
||||||
|
ProjectModel::INode* currentNode() const;
|
||||||
|
const amuse::SoundMacro* soundMacro() const;
|
||||||
|
void setSamplePos(int pos);
|
||||||
|
|
||||||
|
void resizeEvent(QResizeEvent* ev);
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
#endif //AMUSE_SAMPLE_EDITOR_HPP
|
||||||
1777
Editor/SongGroupEditor.cpp
Normal file
301
Editor/SongGroupEditor.hpp
Normal file
@@ -0,0 +1,301 @@
|
|||||||
|
#ifndef AMUSE_SONG_GROUP_EDITOR_HPP
|
||||||
|
#define AMUSE_SONG_GROUP_EDITOR_HPP
|
||||||
|
|
||||||
|
#include "EditorWidget.hpp"
|
||||||
|
#include <QTabWidget>
|
||||||
|
#include <QAbstractTableModel>
|
||||||
|
#include <QTableView>
|
||||||
|
#include <QToolButton>
|
||||||
|
#include <QAction>
|
||||||
|
#include <QSplitter>
|
||||||
|
#include <QListView>
|
||||||
|
#include <QLineEdit>
|
||||||
|
#include <QPushButton>
|
||||||
|
#include <QFileDialog>
|
||||||
|
#include <QProxyStyle>
|
||||||
|
#include "amuse/Sequencer.hpp"
|
||||||
|
|
||||||
|
class SetupTableView;
|
||||||
|
|
||||||
|
class PageObjectDelegate : public BaseObjectDelegate
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
protected:
|
||||||
|
ProjectModel::INode* getNode(const QAbstractItemModel* model, const QModelIndex& index) const;
|
||||||
|
public:
|
||||||
|
explicit PageObjectDelegate(QObject* parent = Q_NULLPTR);
|
||||||
|
QWidget* createEditor(QWidget* parent, const QStyleOptionViewItem& option, const QModelIndex& index) const;
|
||||||
|
void setEditorData(QWidget* editor, const QModelIndex& index) const;
|
||||||
|
void setModelData(QWidget* editor, QAbstractItemModel* model, const QModelIndex& index) const;
|
||||||
|
private slots:
|
||||||
|
void objIndexChanged();
|
||||||
|
};
|
||||||
|
|
||||||
|
class MIDIFileFieldWidget : public QWidget
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
QLineEdit m_le;
|
||||||
|
QPushButton m_button;
|
||||||
|
QFileDialog m_dialog;
|
||||||
|
public:
|
||||||
|
explicit MIDIFileFieldWidget(QWidget* parent = Q_NULLPTR);
|
||||||
|
QString path() const { return m_le.text(); }
|
||||||
|
void setPath(const QString& path) { m_le.setText(path); }
|
||||||
|
public slots:
|
||||||
|
void buttonPressed();
|
||||||
|
void fileDialogOpened(const QString& path);
|
||||||
|
signals:
|
||||||
|
void pathChanged();
|
||||||
|
};
|
||||||
|
|
||||||
|
class MIDIFileDelegate : public QStyledItemDelegate
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
QFileDialog m_fileDialogMid, m_fileDialogSng;
|
||||||
|
std::vector<uint8_t> m_exportData;
|
||||||
|
public:
|
||||||
|
explicit MIDIFileDelegate(SetupTableView* parent = Q_NULLPTR);
|
||||||
|
QWidget* createEditor(QWidget* parent, const QStyleOptionViewItem& option, const QModelIndex& index) const;
|
||||||
|
void destroyEditor(QWidget *editor, const QModelIndex &index) const;
|
||||||
|
void setEditorData(QWidget* editor, const QModelIndex& index) const;
|
||||||
|
void setModelData(QWidget* editor, QAbstractItemModel* model, const QModelIndex& index) const;
|
||||||
|
bool editorEvent(QEvent *event, QAbstractItemModel *model,
|
||||||
|
const QStyleOptionViewItem &option, const QModelIndex &index);
|
||||||
|
private slots:
|
||||||
|
void doExportMIDI();
|
||||||
|
void _doExportMIDI(const QString& path);
|
||||||
|
void doExportSNG();
|
||||||
|
void _doExportSNG(const QString& path);
|
||||||
|
public slots:
|
||||||
|
void pathChanged();
|
||||||
|
};
|
||||||
|
|
||||||
|
class PageModel : public QAbstractTableModel
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
friend class SongGroupEditor;
|
||||||
|
friend class PageObjectDelegate;
|
||||||
|
friend class PageTableView;
|
||||||
|
amuse::ObjToken<ProjectModel::SongGroupNode> m_node;
|
||||||
|
struct Iterator
|
||||||
|
{
|
||||||
|
using ItTp = std::unordered_map<uint8_t, amuse::SongGroupIndex::PageEntry>::iterator;
|
||||||
|
ItTp m_it;
|
||||||
|
Iterator(ItTp it) : m_it(it) {}
|
||||||
|
ItTp::pointer operator->() { return m_it.operator->(); }
|
||||||
|
bool operator<(const Iterator& other) const { return m_it->first < other.m_it->first; }
|
||||||
|
bool operator<(uint8_t other) const { return m_it->first < other; }
|
||||||
|
};
|
||||||
|
std::vector<Iterator> m_sorted;
|
||||||
|
bool m_drum;
|
||||||
|
std::unordered_map<uint8_t, amuse::SongGroupIndex::PageEntry>& _getMap() const;
|
||||||
|
void _buildSortedList();
|
||||||
|
QModelIndex _indexOfProgram(uint8_t prog) const;
|
||||||
|
int _hypotheticalIndexOfProgram(uint8_t prog) const;
|
||||||
|
public:
|
||||||
|
explicit PageModel(bool drum, QObject* parent = Q_NULLPTR);
|
||||||
|
void loadData(ProjectModel::SongGroupNode* node);
|
||||||
|
void unloadData();
|
||||||
|
|
||||||
|
int rowCount(const QModelIndex& parent = QModelIndex()) const;
|
||||||
|
int columnCount(const QModelIndex& parent = QModelIndex()) const;
|
||||||
|
QVariant data(const QModelIndex& index, int role = Qt::DisplayRole) const;
|
||||||
|
bool setData(const QModelIndex& index, const QVariant& value, int role = Qt::EditRole);
|
||||||
|
QVariant headerData(int section, Qt::Orientation orientation, int role = Qt::DisplayRole) const;
|
||||||
|
Qt::ItemFlags flags(const QModelIndex& index) const;
|
||||||
|
|
||||||
|
int _insertRow(const std::pair<uint8_t, amuse::SongGroupIndex::PageEntry>& data);
|
||||||
|
std::pair<uint8_t, amuse::SongGroupIndex::PageEntry> _removeRow(uint8_t prog);
|
||||||
|
};
|
||||||
|
|
||||||
|
class SetupListModel : public QAbstractTableModel
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
friend class SongGroupEditor;
|
||||||
|
friend class MIDIFileDelegate;
|
||||||
|
friend class SetupTableView;
|
||||||
|
friend class SetupModel;
|
||||||
|
amuse::ObjToken<ProjectModel::SongGroupNode> m_node;
|
||||||
|
struct Iterator
|
||||||
|
{
|
||||||
|
using ItTp = std::unordered_map<amuse::SongId, std::array<amuse::SongGroupIndex::MIDISetup, 16>>::iterator;
|
||||||
|
ItTp m_it;
|
||||||
|
Iterator(ItTp it) : m_it(it) {}
|
||||||
|
ItTp::pointer operator->() { return m_it.operator->(); }
|
||||||
|
bool operator<(const Iterator& other) const
|
||||||
|
{
|
||||||
|
return amuse::SongId::CurNameDB->resolveNameFromId(m_it->first) <
|
||||||
|
amuse::SongId::CurNameDB->resolveNameFromId(other.m_it->first);
|
||||||
|
}
|
||||||
|
bool operator<(amuse::SongId other) const
|
||||||
|
{
|
||||||
|
return amuse::SongId::CurNameDB->resolveNameFromId(m_it->first) <
|
||||||
|
amuse::SongId::CurNameDB->resolveNameFromId(other);
|
||||||
|
}
|
||||||
|
bool operator<(const std::string& name) const
|
||||||
|
{
|
||||||
|
return amuse::SongId::CurNameDB->resolveNameFromId(m_it->first) < name;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
std::vector<Iterator> m_sorted;
|
||||||
|
std::unordered_map<amuse::SongId, std::array<amuse::SongGroupIndex::MIDISetup, 16>>& _getMap() const;
|
||||||
|
void _buildSortedList();
|
||||||
|
QModelIndex _indexOfSong(amuse::SongId id) const;
|
||||||
|
int _hypotheticalIndexOfSong(const std::string& songName) const;
|
||||||
|
public:
|
||||||
|
explicit SetupListModel(QObject* parent = Q_NULLPTR);
|
||||||
|
void loadData(ProjectModel::SongGroupNode* node);
|
||||||
|
void unloadData();
|
||||||
|
|
||||||
|
int rowCount(const QModelIndex& parent = QModelIndex()) const;
|
||||||
|
int columnCount(const QModelIndex& parent = QModelIndex()) const;
|
||||||
|
QVariant data(const QModelIndex& index, int role = Qt::DisplayRole) const;
|
||||||
|
bool setData(const QModelIndex& index, const QVariant& value, int role = Qt::EditRole);
|
||||||
|
QVariant headerData(int section, Qt::Orientation orientation, int role = Qt::DisplayRole) const;
|
||||||
|
Qt::ItemFlags flags(const QModelIndex& index) const;
|
||||||
|
|
||||||
|
int _insertRow(
|
||||||
|
std::tuple<amuse::SongId, std::string, std::array<amuse::SongGroupIndex::MIDISetup, 16>>& data);
|
||||||
|
std::tuple<amuse::SongId, std::string, std::array<amuse::SongGroupIndex::MIDISetup, 16>>
|
||||||
|
_removeRow(amuse::SongId id);
|
||||||
|
};
|
||||||
|
|
||||||
|
class SetupModel : public QAbstractTableModel
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
friend class SongGroupEditor;
|
||||||
|
std::pair<const amuse::SongId, std::array<amuse::SongGroupIndex::MIDISetup, 16>>* m_data = nullptr;
|
||||||
|
public:
|
||||||
|
explicit SetupModel(QObject* parent = Q_NULLPTR);
|
||||||
|
void loadData(std::pair<const amuse::SongId, std::array<amuse::SongGroupIndex::MIDISetup, 16>>* data);
|
||||||
|
void unloadData();
|
||||||
|
|
||||||
|
int rowCount(const QModelIndex& parent = QModelIndex()) const;
|
||||||
|
int columnCount(const QModelIndex& parent = QModelIndex()) const;
|
||||||
|
QVariant data(const QModelIndex& index, int role = Qt::DisplayRole) const;
|
||||||
|
bool setData(const QModelIndex& index, const QVariant& value, int role = Qt::EditRole);
|
||||||
|
QVariant headerData(int section, Qt::Orientation orientation, int role = Qt::DisplayRole) const;
|
||||||
|
Qt::ItemFlags flags(const QModelIndex& index) const;
|
||||||
|
};
|
||||||
|
|
||||||
|
class PageTableView : public QTableView
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
PageObjectDelegate m_poDelegate;
|
||||||
|
RangedValueFactory<0, 127> m_127Factory;
|
||||||
|
RangedValueFactory<1, 128> m_128Factory;
|
||||||
|
RangedValueFactory<0, 255> m_255Factory;
|
||||||
|
QStyledItemDelegate m_127Delegate, m_128Delegate, m_255Delegate;
|
||||||
|
public:
|
||||||
|
explicit PageTableView(QWidget* parent = Q_NULLPTR);
|
||||||
|
void setModel(QAbstractItemModel* model);
|
||||||
|
void deleteSelection();
|
||||||
|
};
|
||||||
|
|
||||||
|
class SetupTableView : public QSplitter
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
friend class SongGroupEditor;
|
||||||
|
friend class SetupRowUndoCommand;
|
||||||
|
QTableView* m_listView;
|
||||||
|
QTableView* m_tableView;
|
||||||
|
MIDIFileDelegate m_midiDelegate;
|
||||||
|
RangedValueFactory<0, 127> m_127Factory;
|
||||||
|
RangedValueFactory<1, 128> m_128Factory;
|
||||||
|
QStyledItemDelegate m_127Delegate, m_128Delegate;
|
||||||
|
public:
|
||||||
|
explicit SetupTableView(QWidget* parent = Q_NULLPTR);
|
||||||
|
void setModel(QAbstractItemModel* list, QAbstractItemModel* table);
|
||||||
|
void deleteSelection();
|
||||||
|
void showEvent(QShowEvent* event);
|
||||||
|
};
|
||||||
|
|
||||||
|
class ColoredTabBarStyle : public QProxyStyle
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
using QProxyStyle::QProxyStyle;
|
||||||
|
void drawControl(QStyle::ControlElement element, const QStyleOption *option,
|
||||||
|
QPainter *painter, const QWidget *widget = nullptr) const;
|
||||||
|
};
|
||||||
|
|
||||||
|
class ColoredTabBar : public QTabBar
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
public:
|
||||||
|
explicit ColoredTabBar(QWidget* parent = Q_NULLPTR);
|
||||||
|
};
|
||||||
|
|
||||||
|
class ColoredTabWidget : public QTabWidget
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
ColoredTabBar m_tabBar;
|
||||||
|
public:
|
||||||
|
explicit ColoredTabWidget(QWidget* parent = Q_NULLPTR);
|
||||||
|
};
|
||||||
|
|
||||||
|
class MIDIPlayerWidget : public QWidget
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
QAction m_playAction;
|
||||||
|
QToolButton m_button;
|
||||||
|
QModelIndex m_index;
|
||||||
|
amuse::GroupId m_groupId;
|
||||||
|
amuse::SongId m_songId;
|
||||||
|
QString m_path;
|
||||||
|
std::vector<uint8_t> m_arrData;
|
||||||
|
amuse::ObjToken<amuse::Sequencer> m_seq;
|
||||||
|
public:
|
||||||
|
explicit MIDIPlayerWidget(QModelIndex index, amuse::GroupId gid, amuse::SongId id,
|
||||||
|
const QString& path, QWidget* parent = Q_NULLPTR);
|
||||||
|
~MIDIPlayerWidget();
|
||||||
|
amuse::SongId songId() const { return m_songId; }
|
||||||
|
amuse::Sequencer* sequencer() const { return m_seq.get(); }
|
||||||
|
void stopped();
|
||||||
|
void resizeEvent(QResizeEvent* event);
|
||||||
|
void mouseDoubleClickEvent(QMouseEvent* event);
|
||||||
|
void mousePressEvent(QMouseEvent* event);
|
||||||
|
void mouseReleaseEvent(QMouseEvent* event) { event->ignore(); }
|
||||||
|
public slots:
|
||||||
|
void clicked();
|
||||||
|
};
|
||||||
|
|
||||||
|
class SongGroupEditor : public EditorWidget
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
friend class SetupModel;
|
||||||
|
PageModel m_normPages;
|
||||||
|
PageModel m_drumPages;
|
||||||
|
SetupListModel m_setupList;
|
||||||
|
SetupModel m_setup;
|
||||||
|
PageTableView* m_normTable;
|
||||||
|
PageTableView* m_drumTable;
|
||||||
|
SetupTableView* m_setupTable;
|
||||||
|
ColoredTabWidget m_tabs;
|
||||||
|
AddRemoveButtons m_addRemoveButtons;
|
||||||
|
public:
|
||||||
|
explicit SongGroupEditor(QWidget* parent = Q_NULLPTR);
|
||||||
|
bool loadData(ProjectModel::SongGroupNode* node);
|
||||||
|
void unloadData();
|
||||||
|
ProjectModel::INode* currentNode() const;
|
||||||
|
void setEditorEnabled(bool en) {}
|
||||||
|
void resizeEvent(QResizeEvent* ev);
|
||||||
|
QTableView* getSetupListView() const { return m_setupTable->m_listView; }
|
||||||
|
AmuseItemEditFlags itemEditFlags() const;
|
||||||
|
private slots:
|
||||||
|
void doAdd();
|
||||||
|
void doSelectionChanged();
|
||||||
|
void doSetupSelectionChanged();
|
||||||
|
void currentTabChanged(int idx);
|
||||||
|
void normRowsInserted(const QModelIndex& parent, int first, int last);
|
||||||
|
void normRowsMoved(const QModelIndex& parent, int start, int end, const QModelIndex& destination, int row);
|
||||||
|
void drumRowsInserted(const QModelIndex& parent, int first, int last);
|
||||||
|
void drumRowsMoved(const QModelIndex& parent, int start, int end, const QModelIndex& destination, int row);
|
||||||
|
void setupRowsInserted(const QModelIndex& parent, int first, int last);
|
||||||
|
void setupRowsMoved(const QModelIndex& parent, int start, int end, const QModelIndex& destination, int row);
|
||||||
|
void setupRowsAboutToBeRemoved(const QModelIndex &parent, int first, int last);
|
||||||
|
void setupModelAboutToBeReset();
|
||||||
|
void setupDataChanged();
|
||||||
|
void itemDeleteAction();
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif //AMUSE_SONG_GROUP_EDITOR_HPP
|
||||||
704
Editor/SoundGroupEditor.cpp
Normal file
@@ -0,0 +1,704 @@
|
|||||||
|
#include "SoundGroupEditor.hpp"
|
||||||
|
#include "MainWindow.hpp"
|
||||||
|
|
||||||
|
class SFXDataChangeUndoCommand : public EditorUndoCommand
|
||||||
|
{
|
||||||
|
amuse::SFXId m_sfx;
|
||||||
|
int m_column;
|
||||||
|
int m_undoVal, m_redoVal;
|
||||||
|
bool m_undid = false;
|
||||||
|
public:
|
||||||
|
explicit SFXDataChangeUndoCommand(ProjectModel::SoundGroupNode* node, const QString& text,
|
||||||
|
amuse::SFXId sfx, int column, int redoVal)
|
||||||
|
: EditorUndoCommand(node, text), m_sfx(sfx), m_column(column), m_redoVal(redoVal) {}
|
||||||
|
void undo()
|
||||||
|
{
|
||||||
|
m_undid = true;
|
||||||
|
amuse::SFXGroupIndex& index = *static_cast<ProjectModel::SoundGroupNode*>(m_node.get())->m_index;
|
||||||
|
auto& map = index.m_sfxEntries;
|
||||||
|
amuse::SFXGroupIndex::SFXEntry& entry = map[m_sfx];
|
||||||
|
|
||||||
|
switch (m_column)
|
||||||
|
{
|
||||||
|
case 1:
|
||||||
|
entry.objId.id = m_undoVal;
|
||||||
|
break;
|
||||||
|
case 2:
|
||||||
|
entry.priority = m_undoVal;
|
||||||
|
break;
|
||||||
|
case 3:
|
||||||
|
entry.maxVoices = m_undoVal;
|
||||||
|
break;
|
||||||
|
case 4:
|
||||||
|
entry.defVel = m_undoVal;
|
||||||
|
break;
|
||||||
|
case 5:
|
||||||
|
entry.panning = m_undoVal;
|
||||||
|
break;
|
||||||
|
case 6:
|
||||||
|
entry.defKey = m_undoVal;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
EditorUndoCommand::undo();
|
||||||
|
}
|
||||||
|
void redo()
|
||||||
|
{
|
||||||
|
amuse::SFXGroupIndex& index = *static_cast<ProjectModel::SoundGroupNode*>(m_node.get())->m_index;
|
||||||
|
auto& map = index.m_sfxEntries;
|
||||||
|
amuse::SFXGroupIndex::SFXEntry& entry = map[m_sfx];
|
||||||
|
|
||||||
|
switch (m_column)
|
||||||
|
{
|
||||||
|
case 1:
|
||||||
|
m_undoVal = entry.objId.id;
|
||||||
|
entry.objId.id = m_redoVal;
|
||||||
|
break;
|
||||||
|
case 2:
|
||||||
|
m_undoVal = entry.priority;
|
||||||
|
entry.priority = m_redoVal;
|
||||||
|
break;
|
||||||
|
case 3:
|
||||||
|
m_undoVal = entry.maxVoices;
|
||||||
|
entry.maxVoices = m_redoVal;
|
||||||
|
break;
|
||||||
|
case 4:
|
||||||
|
m_undoVal = entry.defVel;
|
||||||
|
entry.defVel = m_redoVal;
|
||||||
|
break;
|
||||||
|
case 5:
|
||||||
|
m_undoVal = entry.panning;
|
||||||
|
entry.panning = m_redoVal;
|
||||||
|
break;
|
||||||
|
case 6:
|
||||||
|
m_undoVal = entry.defKey;
|
||||||
|
entry.defKey = m_redoVal;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (m_undid)
|
||||||
|
EditorUndoCommand::redo();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
class SFXNameChangeUndoCommand : public EditorUndoCommand
|
||||||
|
{
|
||||||
|
amuse::SFXId m_sfx;
|
||||||
|
std::string m_undoVal, m_redoVal;
|
||||||
|
bool m_undid = false;
|
||||||
|
public:
|
||||||
|
explicit SFXNameChangeUndoCommand(ProjectModel::SoundGroupNode* node, const QString& text,
|
||||||
|
amuse::SFXId sfx, std::string_view redoVal)
|
||||||
|
: EditorUndoCommand(node, text), m_sfx(sfx), m_redoVal(redoVal) {}
|
||||||
|
void undo()
|
||||||
|
{
|
||||||
|
m_undid = true;
|
||||||
|
g_MainWindow->projectModel()->setIdDatabases(m_node.get());
|
||||||
|
amuse::SFXGroupIndex& index = *static_cast<ProjectModel::SoundGroupNode*>(m_node.get())->m_index;
|
||||||
|
auto& map = index.m_sfxEntries;
|
||||||
|
|
||||||
|
amuse::SFXId::CurNameDB->rename(m_sfx, m_undoVal);
|
||||||
|
|
||||||
|
EditorUndoCommand::undo();
|
||||||
|
}
|
||||||
|
void redo()
|
||||||
|
{
|
||||||
|
g_MainWindow->projectModel()->setIdDatabases(m_node.get());
|
||||||
|
amuse::SFXGroupIndex& index = *static_cast<ProjectModel::SoundGroupNode*>(m_node.get())->m_index;
|
||||||
|
auto& map = index.m_sfxEntries;
|
||||||
|
|
||||||
|
m_undoVal = amuse::SFXId::CurNameDB->resolveNameFromId(m_sfx);
|
||||||
|
amuse::SFXId::CurNameDB->rename(m_sfx, m_redoVal);
|
||||||
|
|
||||||
|
if (m_undid)
|
||||||
|
EditorUndoCommand::redo();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
SFXObjectDelegate::SFXObjectDelegate(QObject* parent)
|
||||||
|
: BaseObjectDelegate(parent) {}
|
||||||
|
|
||||||
|
ProjectModel::INode* SFXObjectDelegate::getNode(const QAbstractItemModel* __model, const QModelIndex& index) const
|
||||||
|
{
|
||||||
|
const SFXModel* model = static_cast<const SFXModel*>(__model);
|
||||||
|
auto entry = model->m_sorted[index.row()];
|
||||||
|
if (entry->second.objId.id.id == 0xffff)
|
||||||
|
return nullptr;
|
||||||
|
ProjectModel::GroupNode* group = g_MainWindow->projectModel()->getGroupNode(model->m_node.get());
|
||||||
|
return group->pageObjectNodeOfId(entry->second.objId.id);
|
||||||
|
}
|
||||||
|
|
||||||
|
QWidget* SFXObjectDelegate::createEditor(QWidget* parent, const QStyleOptionViewItem& option, const QModelIndex& index) const
|
||||||
|
{
|
||||||
|
const SFXModel* model = static_cast<const SFXModel*>(index.model());
|
||||||
|
ProjectModel::GroupNode* group = g_MainWindow->projectModel()->getGroupNode(model->m_node.get());
|
||||||
|
EditorFieldPageObjectNode* cb = new EditorFieldPageObjectNode(group, parent);
|
||||||
|
connect(cb, SIGNAL(currentIndexChanged(int)), this, SLOT(objIndexChanged()));
|
||||||
|
return cb;
|
||||||
|
}
|
||||||
|
|
||||||
|
void SFXObjectDelegate::setEditorData(QWidget* editor, const QModelIndex& index) const
|
||||||
|
{
|
||||||
|
int idx = 0;
|
||||||
|
if (ProjectModel::BasePoolObjectNode* node = static_cast<ProjectModel::BasePoolObjectNode*>(getNode(index.model(), index)))
|
||||||
|
idx = g_MainWindow->projectModel()->getPageObjectProxy()->mapFromSource(g_MainWindow->projectModel()->index(node)).row();
|
||||||
|
static_cast<EditorFieldPageObjectNode*>(editor)->setCurrentIndex(idx);
|
||||||
|
if (static_cast<EditorFieldPageObjectNode*>(editor)->shouldPopupOpen())
|
||||||
|
QApplication::postEvent(editor, new QEvent(QEvent::User));
|
||||||
|
}
|
||||||
|
|
||||||
|
void SFXObjectDelegate::setModelData(QWidget* editor, QAbstractItemModel* m, const QModelIndex& index) const
|
||||||
|
{
|
||||||
|
const SFXModel* model = static_cast<const SFXModel*>(m);
|
||||||
|
auto entry = model->m_sorted[index.row()];
|
||||||
|
ProjectModel::BasePoolObjectNode* node = static_cast<EditorFieldPageObjectNode*>(editor)->currentNode();
|
||||||
|
amuse::ObjectId id;
|
||||||
|
if (node)
|
||||||
|
id = node->id();
|
||||||
|
if (id == entry->second.objId.id)
|
||||||
|
{
|
||||||
|
emit m->dataChanged(index, index);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
g_MainWindow->pushUndoCommand(new SFXDataChangeUndoCommand(model->m_node.get(),
|
||||||
|
tr("Change %1").arg(m->headerData(1, Qt::Horizontal).toString()), entry->first, 1, id.id));
|
||||||
|
emit m->dataChanged(index, index);
|
||||||
|
}
|
||||||
|
|
||||||
|
void SFXObjectDelegate::objIndexChanged()
|
||||||
|
{
|
||||||
|
emit commitData(static_cast<QWidget*>(sender()));
|
||||||
|
}
|
||||||
|
|
||||||
|
std::unordered_map<amuse::SFXId, amuse::SFXGroupIndex::SFXEntry>& SFXModel::_getMap() const
|
||||||
|
{
|
||||||
|
return m_node->m_index->m_sfxEntries;
|
||||||
|
}
|
||||||
|
|
||||||
|
void SFXModel::_buildSortedList()
|
||||||
|
{
|
||||||
|
m_sorted.clear();
|
||||||
|
if (!m_node)
|
||||||
|
return;
|
||||||
|
auto& map = _getMap();
|
||||||
|
m_sorted.reserve(map.size());
|
||||||
|
for (auto it = map.begin() ; it != map.end() ; ++it)
|
||||||
|
m_sorted.emplace_back(it);
|
||||||
|
std::sort(m_sorted.begin(), m_sorted.end());
|
||||||
|
}
|
||||||
|
|
||||||
|
QModelIndex SFXModel::_indexOfSFX(amuse::SFXId sfx) const
|
||||||
|
{
|
||||||
|
auto search = std::lower_bound(m_sorted.cbegin(), m_sorted.cend(), sfx);
|
||||||
|
if (search == m_sorted.cend() || search->m_it->first != sfx)
|
||||||
|
return QModelIndex();
|
||||||
|
else
|
||||||
|
return createIndex(search - m_sorted.begin(), 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
int SFXModel::_hypotheticalIndexOfSFX(const std::string& sfxName) const
|
||||||
|
{
|
||||||
|
auto search = std::lower_bound(m_sorted.cbegin(), m_sorted.cend(), sfxName);
|
||||||
|
return search - m_sorted.begin();
|
||||||
|
}
|
||||||
|
|
||||||
|
void SFXModel::loadData(ProjectModel::SoundGroupNode* node)
|
||||||
|
{
|
||||||
|
beginResetModel();
|
||||||
|
m_node = node;
|
||||||
|
_buildSortedList();
|
||||||
|
endResetModel();
|
||||||
|
}
|
||||||
|
|
||||||
|
void SFXModel::unloadData()
|
||||||
|
{
|
||||||
|
beginResetModel();
|
||||||
|
m_node.reset();
|
||||||
|
m_sorted.clear();
|
||||||
|
endResetModel();
|
||||||
|
}
|
||||||
|
|
||||||
|
int SFXModel::rowCount(const QModelIndex& parent) const
|
||||||
|
{
|
||||||
|
if (parent.isValid())
|
||||||
|
return 0;
|
||||||
|
if (!m_node)
|
||||||
|
return 0;
|
||||||
|
return int(m_sorted.size()) + 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
int SFXModel::columnCount(const QModelIndex& parent) const
|
||||||
|
{
|
||||||
|
if (parent.isValid())
|
||||||
|
return 0;
|
||||||
|
return 7;
|
||||||
|
}
|
||||||
|
|
||||||
|
QVariant SFXModel::data(const QModelIndex& index, int role) const
|
||||||
|
{
|
||||||
|
if (!m_node)
|
||||||
|
return QVariant();
|
||||||
|
if (index.row() == m_sorted.size())
|
||||||
|
return QVariant();
|
||||||
|
|
||||||
|
auto entry = m_sorted[index.row()];
|
||||||
|
|
||||||
|
if (role == Qt::DisplayRole || role == Qt::EditRole)
|
||||||
|
{
|
||||||
|
switch (index.column())
|
||||||
|
{
|
||||||
|
case 0:
|
||||||
|
{
|
||||||
|
g_MainWindow->projectModel()->setIdDatabases(m_node.get());
|
||||||
|
return amuse::SFXId::CurNameDB->resolveNameFromId(entry->first.id).data();
|
||||||
|
}
|
||||||
|
case 1:
|
||||||
|
{
|
||||||
|
ProjectModel::GroupNode* group = g_MainWindow->projectModel()->getGroupNode(m_node.get());
|
||||||
|
if (ProjectModel::BasePoolObjectNode* node = group->pageObjectNodeOfId(entry->second.objId.id))
|
||||||
|
return node->text();
|
||||||
|
return QVariant();
|
||||||
|
}
|
||||||
|
case 2:
|
||||||
|
return entry->second.priority;
|
||||||
|
case 3:
|
||||||
|
return entry->second.maxVoices;
|
||||||
|
case 4:
|
||||||
|
return entry->second.defVel;
|
||||||
|
case 5:
|
||||||
|
return entry->second.panning;
|
||||||
|
case 6:
|
||||||
|
return entry->second.defKey;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return QVariant();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool SFXModel::setData(const QModelIndex& index, const QVariant& value, int role)
|
||||||
|
{
|
||||||
|
if (!m_node || role != Qt::EditRole)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
auto& map = _getMap();
|
||||||
|
auto entry = m_sorted[index.row()];
|
||||||
|
|
||||||
|
switch (index.column())
|
||||||
|
{
|
||||||
|
case 0:
|
||||||
|
{
|
||||||
|
g_MainWindow->projectModel()->setIdDatabases(m_node.get());
|
||||||
|
auto utf8key = value.toString().toUtf8();
|
||||||
|
std::unordered_map<std::string, amuse::ObjectId>::iterator idIt;
|
||||||
|
if ((idIt = amuse::SFXId::CurNameDB->m_stringToId.find(utf8key.data())) != amuse::SFXId::CurNameDB->m_stringToId.cend())
|
||||||
|
{
|
||||||
|
if (idIt->second == entry->first)
|
||||||
|
return false;
|
||||||
|
g_MainWindow->uiMessenger().critical(tr("SFX Conflict"),
|
||||||
|
tr("SFX %1 is already defined in project").arg(value.toString()));
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
int newIdx = _hypotheticalIndexOfSFX(utf8key.data());
|
||||||
|
bool moving = beginMoveRows(index.parent(), index.row(), index.row(), index.parent(), newIdx);
|
||||||
|
g_MainWindow->pushUndoCommand(new SFXNameChangeUndoCommand(m_node.get(),
|
||||||
|
tr("Change SFX Name"), entry->first, utf8key.data()));
|
||||||
|
_buildSortedList();
|
||||||
|
if (moving)
|
||||||
|
endMoveRows();
|
||||||
|
QModelIndex newIndex = _indexOfSFX(entry->first);
|
||||||
|
emit dataChanged(newIndex, newIndex, {Qt::DisplayRole, Qt::EditRole});
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
case 2:
|
||||||
|
if (entry->second.priority == value.toInt())
|
||||||
|
return false;
|
||||||
|
break;
|
||||||
|
case 3:
|
||||||
|
if (entry->second.maxVoices == value.toInt())
|
||||||
|
return false;
|
||||||
|
break;
|
||||||
|
case 4:
|
||||||
|
if (entry->second.defVel == value.toInt())
|
||||||
|
return false;
|
||||||
|
break;
|
||||||
|
case 5:
|
||||||
|
if (entry->second.panning == value.toInt())
|
||||||
|
return false;
|
||||||
|
break;
|
||||||
|
case 6:
|
||||||
|
if (entry->second.defKey == value.toInt())
|
||||||
|
return false;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
g_MainWindow->pushUndoCommand(new SFXDataChangeUndoCommand(m_node.get(),
|
||||||
|
tr("Change %1").arg(headerData(index.column(), Qt::Horizontal).toString()),
|
||||||
|
entry->first, index.column(), value.toInt()));
|
||||||
|
emit dataChanged(index, index, {Qt::DisplayRole, Qt::EditRole});
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
QVariant SFXModel::headerData(int section, Qt::Orientation orientation, int role) const
|
||||||
|
{
|
||||||
|
if (orientation == Qt::Horizontal && role == Qt::DisplayRole)
|
||||||
|
{
|
||||||
|
switch (section)
|
||||||
|
{
|
||||||
|
case 0:
|
||||||
|
return tr("SFX");
|
||||||
|
case 1:
|
||||||
|
return tr("Object");
|
||||||
|
case 2:
|
||||||
|
return tr("Priority");
|
||||||
|
case 3:
|
||||||
|
return tr("Max Voices");
|
||||||
|
case 4:
|
||||||
|
return tr("Velocity");
|
||||||
|
case 5:
|
||||||
|
return tr("Panning");
|
||||||
|
case 6:
|
||||||
|
return tr("Key");
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return QVariant();
|
||||||
|
}
|
||||||
|
|
||||||
|
Qt::ItemFlags SFXModel::flags(const QModelIndex& index) const
|
||||||
|
{
|
||||||
|
if (!index.isValid())
|
||||||
|
return Qt::NoItemFlags;
|
||||||
|
if (index.row() == m_sorted.size())
|
||||||
|
return Qt::NoItemFlags;
|
||||||
|
return Qt::ItemIsSelectable | Qt::ItemIsEnabled | Qt::ItemIsEditable;
|
||||||
|
}
|
||||||
|
|
||||||
|
class SFXRowUndoCommand : public EditorUndoCommand
|
||||||
|
{
|
||||||
|
protected:
|
||||||
|
SFXTableView* m_view;
|
||||||
|
std::vector<std::tuple<amuse::SFXId, std::string, amuse::SFXGroupIndex::SFXEntry>> m_data;
|
||||||
|
bool m_undid = false;
|
||||||
|
void add()
|
||||||
|
{
|
||||||
|
m_view->selectionModel()->clearSelection();
|
||||||
|
for (auto& p : m_data)
|
||||||
|
{
|
||||||
|
int row = static_cast<SFXModel*>(m_view->model())->_insertRow(p);
|
||||||
|
m_view->setCurrentIndex(m_view->model()->index(row, 0));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
void del()
|
||||||
|
{
|
||||||
|
for (auto it = m_data.rbegin(); it != m_data.rend(); ++it)
|
||||||
|
{
|
||||||
|
*it = static_cast<SFXModel*>(m_view->model())->_removeRow(std::get<0>(*it));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
void undo()
|
||||||
|
{
|
||||||
|
m_undid = true;
|
||||||
|
EditorUndoCommand::undo();
|
||||||
|
}
|
||||||
|
void redo()
|
||||||
|
{
|
||||||
|
if (m_undid)
|
||||||
|
EditorUndoCommand::redo();
|
||||||
|
}
|
||||||
|
public:
|
||||||
|
explicit SFXRowUndoCommand(ProjectModel::SoundGroupNode* node, const QString& text, SFXTableView* view,
|
||||||
|
std::vector<std::tuple<amuse::SFXId, std::string, amuse::SFXGroupIndex::SFXEntry>>&& data)
|
||||||
|
: EditorUndoCommand(node, text), m_view(view), m_data(std::move(data)) {}
|
||||||
|
};
|
||||||
|
|
||||||
|
class SFXRowAddUndoCommand : public SFXRowUndoCommand
|
||||||
|
{
|
||||||
|
using base = SFXRowUndoCommand;
|
||||||
|
public:
|
||||||
|
explicit SFXRowAddUndoCommand(ProjectModel::SoundGroupNode* node, const QString& text, SFXTableView* view,
|
||||||
|
std::vector<std::tuple<amuse::SFXId, std::string, amuse::SFXGroupIndex::SFXEntry>>&& data)
|
||||||
|
: SFXRowUndoCommand(node, text, view, std::move(data)) {}
|
||||||
|
void undo() { base::undo(); base::del(); }
|
||||||
|
void redo() { base::redo(); base::add(); }
|
||||||
|
};
|
||||||
|
|
||||||
|
class SFXRowDelUndoCommand : public SFXRowUndoCommand
|
||||||
|
{
|
||||||
|
using base = SFXRowUndoCommand;
|
||||||
|
public:
|
||||||
|
explicit SFXRowDelUndoCommand(ProjectModel::SoundGroupNode* node, const QString& text, SFXTableView* view,
|
||||||
|
std::vector<std::tuple<amuse::SFXId, std::string, amuse::SFXGroupIndex::SFXEntry>>&& data)
|
||||||
|
: SFXRowUndoCommand(node, text, view, std::move(data)) {}
|
||||||
|
void undo() { base::undo(); base::add(); }
|
||||||
|
void redo() { base::redo(); base::del(); }
|
||||||
|
};
|
||||||
|
|
||||||
|
int SFXModel::_insertRow(const std::tuple<amuse::SFXId, std::string, amuse::SFXGroupIndex::SFXEntry>& data)
|
||||||
|
{
|
||||||
|
if (!m_node)
|
||||||
|
return 0;
|
||||||
|
auto& map = _getMap();
|
||||||
|
g_MainWindow->projectModel()->setIdDatabases(m_node.get());
|
||||||
|
amuse::SFXId::CurNameDB->registerPair(std::get<1>(data), std::get<0>(data));
|
||||||
|
int idx = _hypotheticalIndexOfSFX(std::get<1>(data));
|
||||||
|
beginInsertRows(QModelIndex(), idx, idx);
|
||||||
|
map.emplace(std::make_pair(std::get<0>(data), std::get<2>(data)));
|
||||||
|
_buildSortedList();
|
||||||
|
endInsertRows();
|
||||||
|
return idx;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::tuple<amuse::SFXId, std::string, amuse::SFXGroupIndex::SFXEntry> SFXModel::_removeRow(amuse::SFXId sfx)
|
||||||
|
{
|
||||||
|
std::tuple<amuse::SFXId, std::string, amuse::SFXGroupIndex::SFXEntry> ret;
|
||||||
|
if (!m_node)
|
||||||
|
return ret;
|
||||||
|
auto& map = _getMap();
|
||||||
|
g_MainWindow->projectModel()->setIdDatabases(m_node.get());
|
||||||
|
int idx = _indexOfSFX(sfx).row();
|
||||||
|
beginRemoveRows(QModelIndex(), idx, idx);
|
||||||
|
std::get<0>(ret) = sfx;
|
||||||
|
std::get<1>(ret) = amuse::SFXId::CurNameDB->resolveNameFromId(sfx);
|
||||||
|
auto search = map.find(sfx);
|
||||||
|
if (search != map.cend())
|
||||||
|
{
|
||||||
|
std::get<2>(ret) = search->second;
|
||||||
|
amuse::SFXId::CurNameDB->remove(sfx);
|
||||||
|
map.erase(search);
|
||||||
|
}
|
||||||
|
_buildSortedList();
|
||||||
|
endRemoveRows();
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
SFXModel::SFXModel(QObject* parent)
|
||||||
|
: QAbstractTableModel(parent)
|
||||||
|
{}
|
||||||
|
|
||||||
|
void SFXTableView::deleteSelection()
|
||||||
|
{
|
||||||
|
QModelIndexList list = selectionModel()->selectedRows();
|
||||||
|
if (list.isEmpty())
|
||||||
|
return;
|
||||||
|
std::sort(list.begin(), list.end(), [](const auto& a, const auto& b) { return a.row() < b.row(); });
|
||||||
|
std::vector<std::tuple<amuse::SFXId, std::string, amuse::SFXGroupIndex::SFXEntry>> data;
|
||||||
|
data.reserve(list.size());
|
||||||
|
for (QModelIndex idx : list)
|
||||||
|
{
|
||||||
|
auto& entry = *static_cast<SFXModel*>(model())->m_sorted[idx.row()].m_it;
|
||||||
|
data.push_back({entry.first, {}, {}});
|
||||||
|
}
|
||||||
|
g_MainWindow->pushUndoCommand(
|
||||||
|
new SFXRowDelUndoCommand(static_cast<SFXModel*>(model())->m_node.get(),
|
||||||
|
data.size() > 1 ? tr("Delete SFX Entries") : tr("Delete SFX Entry"), this, std::move(data)));
|
||||||
|
}
|
||||||
|
|
||||||
|
void SFXTableView::setModel(QAbstractItemModel* model)
|
||||||
|
{
|
||||||
|
QTableView::setModel(model);
|
||||||
|
horizontalHeader()->setMinimumSectionSize(75);
|
||||||
|
horizontalHeader()->resizeSection(0, 200);
|
||||||
|
horizontalHeader()->setSectionResizeMode(1, QHeaderView::Stretch);
|
||||||
|
horizontalHeader()->setSectionResizeMode(2, QHeaderView::Fixed);
|
||||||
|
horizontalHeader()->resizeSection(2, 75);
|
||||||
|
horizontalHeader()->setSectionResizeMode(3, QHeaderView::Fixed);
|
||||||
|
horizontalHeader()->resizeSection(3, 100);
|
||||||
|
horizontalHeader()->setSectionResizeMode(4, QHeaderView::Fixed);
|
||||||
|
horizontalHeader()->resizeSection(4, 75);
|
||||||
|
horizontalHeader()->setSectionResizeMode(5, QHeaderView::Fixed);
|
||||||
|
horizontalHeader()->resizeSection(5, 75);
|
||||||
|
horizontalHeader()->setSectionResizeMode(6, QHeaderView::Fixed);
|
||||||
|
horizontalHeader()->resizeSection(6, 75);
|
||||||
|
}
|
||||||
|
|
||||||
|
SFXTableView::SFXTableView(QWidget* parent)
|
||||||
|
: QTableView(parent)
|
||||||
|
{
|
||||||
|
setSelectionBehavior(QAbstractItemView::SelectRows);
|
||||||
|
setSelectionMode(QAbstractItemView::ExtendedSelection);
|
||||||
|
setGridStyle(Qt::NoPen);
|
||||||
|
|
||||||
|
m_127Delegate.setItemEditorFactory(&m_127Factory);
|
||||||
|
m_255Delegate.setItemEditorFactory(&m_255Factory);
|
||||||
|
|
||||||
|
setItemDelegateForColumn(1, &m_sfxDelegate);
|
||||||
|
setItemDelegateForColumn(2, &m_255Delegate);
|
||||||
|
setItemDelegateForColumn(3, &m_255Delegate);
|
||||||
|
setItemDelegateForColumn(4, &m_127Delegate);
|
||||||
|
setItemDelegateForColumn(5, &m_127Delegate);
|
||||||
|
setItemDelegateForColumn(6, &m_127Delegate);
|
||||||
|
}
|
||||||
|
|
||||||
|
void SFXPlayerWidget::clicked()
|
||||||
|
{
|
||||||
|
if (!m_vox)
|
||||||
|
{
|
||||||
|
m_vox = g_MainWindow->startSFX(m_groupId, m_sfxId);
|
||||||
|
if (m_vox)
|
||||||
|
{
|
||||||
|
m_playAction.setText(tr("Stop"));
|
||||||
|
m_playAction.setIcon(QIcon(QStringLiteral(":/icons/IconStop.svg")));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
stopped();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void SFXPlayerWidget::stopped()
|
||||||
|
{
|
||||||
|
m_vox->keyOff();
|
||||||
|
m_vox.reset();
|
||||||
|
m_playAction.setText(tr("Play"));
|
||||||
|
m_playAction.setIcon(QIcon(QStringLiteral(":/icons/IconSoundMacro.svg")));
|
||||||
|
}
|
||||||
|
|
||||||
|
void SFXPlayerWidget::resizeEvent(QResizeEvent* event)
|
||||||
|
{
|
||||||
|
m_button.setGeometry(event->size().width() - event->size().height(), 0,
|
||||||
|
event->size().height(), event->size().height());
|
||||||
|
}
|
||||||
|
|
||||||
|
void SFXPlayerWidget::mouseDoubleClickEvent(QMouseEvent* event)
|
||||||
|
{
|
||||||
|
qobject_cast<QTableView*>(parentWidget()->parentWidget())->setIndexWidget(m_index, nullptr);
|
||||||
|
event->ignore();
|
||||||
|
}
|
||||||
|
|
||||||
|
void SFXPlayerWidget::mousePressEvent(QMouseEvent* event)
|
||||||
|
{
|
||||||
|
if (event->button() == Qt::RightButton)
|
||||||
|
{
|
||||||
|
QTableView* view = qobject_cast<QTableView*>(parentWidget()->parentWidget());
|
||||||
|
QAbstractItemDelegate* delegate = view->itemDelegateForColumn(1);
|
||||||
|
delegate->editorEvent(event, view->model(), {}, m_index);
|
||||||
|
}
|
||||||
|
event->ignore();
|
||||||
|
}
|
||||||
|
|
||||||
|
SFXPlayerWidget::~SFXPlayerWidget()
|
||||||
|
{
|
||||||
|
if (m_vox)
|
||||||
|
m_vox->keyOff();
|
||||||
|
}
|
||||||
|
|
||||||
|
SFXPlayerWidget::SFXPlayerWidget(QModelIndex index, amuse::GroupId gid, amuse::SFXId id, QWidget* parent)
|
||||||
|
: QWidget(parent), m_button(this), m_playAction(tr("Play")), m_index(index),
|
||||||
|
m_groupId(gid), m_sfxId(id)
|
||||||
|
{
|
||||||
|
m_playAction.setIcon(QIcon(QStringLiteral(":/icons/IconSoundMacro.svg")));
|
||||||
|
m_button.setDefaultAction(&m_playAction);
|
||||||
|
connect(&m_playAction, SIGNAL(triggered()), this, SLOT(clicked()));
|
||||||
|
}
|
||||||
|
|
||||||
|
bool SoundGroupEditor::loadData(ProjectModel::SoundGroupNode* node)
|
||||||
|
{
|
||||||
|
m_sfxs.loadData(node);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void SoundGroupEditor::unloadData()
|
||||||
|
{
|
||||||
|
m_sfxs.unloadData();
|
||||||
|
}
|
||||||
|
|
||||||
|
ProjectModel::INode* SoundGroupEditor::currentNode() const
|
||||||
|
{
|
||||||
|
return m_sfxs.m_node.get();
|
||||||
|
}
|
||||||
|
|
||||||
|
void SoundGroupEditor::resizeEvent(QResizeEvent* ev)
|
||||||
|
{
|
||||||
|
m_sfxTable->setGeometry(QRect({}, ev->size()));
|
||||||
|
m_addRemoveButtons.move(0, ev->size().height() - 32);
|
||||||
|
}
|
||||||
|
|
||||||
|
AmuseItemEditFlags SoundGroupEditor::itemEditFlags() const
|
||||||
|
{
|
||||||
|
return (m_sfxTable->hasFocus() && !m_sfxTable->selectionModel()->selectedRows().isEmpty()) ? AmuseItemDelete : AmuseItemNone;
|
||||||
|
}
|
||||||
|
|
||||||
|
void SoundGroupEditor::doAdd()
|
||||||
|
{
|
||||||
|
g_MainWindow->projectModel()->setIdDatabases(m_sfxs.m_node.get());
|
||||||
|
std::vector<std::tuple<amuse::SFXId, std::string, amuse::SFXGroupIndex::SFXEntry>> data;
|
||||||
|
amuse::SFXId sfxId = amuse::SFXId::CurNameDB->generateId(amuse::NameDB::Type::SFX);
|
||||||
|
std::string sfxName = amuse::SFXId::CurNameDB->generateName(sfxId, amuse::NameDB::Type::SFX);
|
||||||
|
data.push_back(std::make_tuple(sfxId, sfxName, amuse::SFXGroupIndex::SFXEntry{}));
|
||||||
|
g_MainWindow->pushUndoCommand(
|
||||||
|
new SFXRowAddUndoCommand(m_sfxs.m_node.get(), tr("Add SFX Entry"), m_sfxTable, std::move(data)));
|
||||||
|
}
|
||||||
|
|
||||||
|
void SoundGroupEditor::doSelectionChanged()
|
||||||
|
{
|
||||||
|
m_addRemoveButtons.removeAction()->setDisabled(m_sfxTable->selectionModel()->selectedRows().isEmpty());
|
||||||
|
g_MainWindow->updateFocus();
|
||||||
|
}
|
||||||
|
|
||||||
|
void SoundGroupEditor::rowsInserted(const QModelIndex &parent, int first, int last)
|
||||||
|
{
|
||||||
|
m_sfxTable->scrollTo(m_sfxTable->model()->index(first, 0));
|
||||||
|
sfxDataChanged();
|
||||||
|
}
|
||||||
|
|
||||||
|
void SoundGroupEditor::rowsMoved(const QModelIndex &parent, int start, int end, const QModelIndex &destination, int row)
|
||||||
|
{
|
||||||
|
m_sfxTable->scrollTo(m_sfxTable->model()->index(row, 0));
|
||||||
|
sfxDataChanged();
|
||||||
|
}
|
||||||
|
|
||||||
|
void SoundGroupEditor::sfxDataChanged()
|
||||||
|
{
|
||||||
|
int idx = 0;
|
||||||
|
for (const auto& p : m_sfxs.m_sorted)
|
||||||
|
{
|
||||||
|
QModelIndex index = m_sfxs.index(idx, 1);
|
||||||
|
SFXPlayerWidget* w = qobject_cast<SFXPlayerWidget*>(m_sfxTable->indexWidget(index));
|
||||||
|
if (!w || w->sfxId() != p->first)
|
||||||
|
{
|
||||||
|
SFXPlayerWidget* newW = new SFXPlayerWidget(index, m_sfxs.m_node->m_id, p->first, m_sfxTable->viewport());
|
||||||
|
m_sfxTable->setIndexWidget(index, newW);
|
||||||
|
}
|
||||||
|
++idx;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void SoundGroupEditor::itemDeleteAction()
|
||||||
|
{
|
||||||
|
m_sfxTable->deleteSelection();
|
||||||
|
}
|
||||||
|
|
||||||
|
SoundGroupEditor::SoundGroupEditor(QWidget* parent)
|
||||||
|
: EditorWidget(parent), m_sfxs(this), m_sfxTable(new SFXTableView(this)), m_addRemoveButtons(this)
|
||||||
|
{
|
||||||
|
m_sfxTable->setModel(&m_sfxs);
|
||||||
|
connect(m_sfxTable->selectionModel(), SIGNAL(selectionChanged(const QItemSelection&, const QItemSelection&)),
|
||||||
|
this, SLOT(doSelectionChanged()));
|
||||||
|
|
||||||
|
connect(&m_sfxs, SIGNAL(rowsInserted(const QModelIndex&, int, int)),
|
||||||
|
this, SLOT(rowsInserted(const QModelIndex&, int, int)));
|
||||||
|
connect(&m_sfxs, SIGNAL(rowsRemoved(const QModelIndex&, int, int)),
|
||||||
|
this, SLOT(sfxDataChanged()));
|
||||||
|
connect(&m_sfxs, SIGNAL(dataChanged(const QModelIndex&, const QModelIndex&, const QVector<int>&)),
|
||||||
|
this, SLOT(sfxDataChanged()));
|
||||||
|
connect(&m_sfxs, SIGNAL(rowsMoved(const QModelIndex&, int, int, const QModelIndex&, int)),
|
||||||
|
this, SLOT(rowsMoved(const QModelIndex&, int, int, const QModelIndex&, int)));
|
||||||
|
connect(&m_sfxs, SIGNAL(modelReset()),
|
||||||
|
this, SLOT(sfxDataChanged()));
|
||||||
|
|
||||||
|
m_addRemoveButtons.addAction()->setToolTip(tr("Add new SFX entry"));
|
||||||
|
connect(m_addRemoveButtons.addAction(), SIGNAL(triggered(bool)), this, SLOT(doAdd()));
|
||||||
|
m_addRemoveButtons.removeAction()->setToolTip(tr("Remove selected SFX entries"));
|
||||||
|
connect(m_addRemoveButtons.removeAction(), SIGNAL(triggered(bool)), this, SLOT(itemDeleteAction()));
|
||||||
|
}
|
||||||
133
Editor/SoundGroupEditor.hpp
Normal file
@@ -0,0 +1,133 @@
|
|||||||
|
#ifndef AMUSE_SOUND_GROUP_EDITOR_HPP
|
||||||
|
#define AMUSE_SOUND_GROUP_EDITOR_HPP
|
||||||
|
|
||||||
|
#include "EditorWidget.hpp"
|
||||||
|
#include <QStyledItemDelegate>
|
||||||
|
#include <QTableView>
|
||||||
|
#include "amuse/Voice.hpp"
|
||||||
|
|
||||||
|
class SFXObjectDelegate : public BaseObjectDelegate
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
protected:
|
||||||
|
ProjectModel::INode* getNode(const QAbstractItemModel* model, const QModelIndex& index) const;
|
||||||
|
public:
|
||||||
|
explicit SFXObjectDelegate(QObject* parent = Q_NULLPTR);
|
||||||
|
QWidget* createEditor(QWidget* parent, const QStyleOptionViewItem& option, const QModelIndex& index) const;
|
||||||
|
void setEditorData(QWidget* editor, const QModelIndex& index) const;
|
||||||
|
void setModelData(QWidget* editor, QAbstractItemModel* model, const QModelIndex& index) const;
|
||||||
|
private slots:
|
||||||
|
void objIndexChanged();
|
||||||
|
};
|
||||||
|
|
||||||
|
class SFXModel : public QAbstractTableModel
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
friend class SoundGroupEditor;
|
||||||
|
friend class SFXObjectDelegate;
|
||||||
|
friend class SFXTableView;
|
||||||
|
amuse::ObjToken<ProjectModel::SoundGroupNode> m_node;
|
||||||
|
struct Iterator
|
||||||
|
{
|
||||||
|
using ItTp = std::unordered_map<amuse::SFXId, amuse::SFXGroupIndex::SFXEntry>::iterator;
|
||||||
|
ItTp m_it;
|
||||||
|
Iterator(ItTp it) : m_it(it) {}
|
||||||
|
ItTp::pointer operator->() const { return m_it.operator->(); }
|
||||||
|
bool operator<(const Iterator& other) const
|
||||||
|
{
|
||||||
|
return amuse::SFXId::CurNameDB->resolveNameFromId(m_it->first) <
|
||||||
|
amuse::SFXId::CurNameDB->resolveNameFromId(other.m_it->first);
|
||||||
|
}
|
||||||
|
bool operator<(amuse::SongId other) const
|
||||||
|
{
|
||||||
|
return amuse::SFXId::CurNameDB->resolveNameFromId(m_it->first) <
|
||||||
|
amuse::SFXId::CurNameDB->resolveNameFromId(other);
|
||||||
|
}
|
||||||
|
bool operator<(const std::string& name) const
|
||||||
|
{
|
||||||
|
return amuse::SFXId::CurNameDB->resolveNameFromId(m_it->first) < name;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
std::vector<Iterator> m_sorted;
|
||||||
|
std::unordered_map<amuse::SFXId, amuse::SFXGroupIndex::SFXEntry>& _getMap() const;
|
||||||
|
void _buildSortedList();
|
||||||
|
QModelIndex _indexOfSFX(amuse::SFXId sfx) const;
|
||||||
|
int _hypotheticalIndexOfSFX(const std::string& sfxName) const;
|
||||||
|
public:
|
||||||
|
explicit SFXModel(QObject* parent = Q_NULLPTR);
|
||||||
|
void loadData(ProjectModel::SoundGroupNode* node);
|
||||||
|
void unloadData();
|
||||||
|
|
||||||
|
int rowCount(const QModelIndex& parent = QModelIndex()) const;
|
||||||
|
int columnCount(const QModelIndex& parent = QModelIndex()) const;
|
||||||
|
QVariant data(const QModelIndex& index, int role = Qt::DisplayRole) const;
|
||||||
|
bool setData(const QModelIndex& index, const QVariant& value, int role = Qt::EditRole);
|
||||||
|
QVariant headerData(int section, Qt::Orientation orientation, int role = Qt::DisplayRole) const;
|
||||||
|
Qt::ItemFlags flags(const QModelIndex& index) const;
|
||||||
|
|
||||||
|
int _insertRow(const std::tuple<amuse::SFXId, std::string, amuse::SFXGroupIndex::SFXEntry>& data);
|
||||||
|
std::tuple<amuse::SFXId, std::string, amuse::SFXGroupIndex::SFXEntry> _removeRow(amuse::SFXId sfx);
|
||||||
|
};
|
||||||
|
|
||||||
|
class SFXTableView : public QTableView
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
SFXObjectDelegate m_sfxDelegate;
|
||||||
|
RangedValueFactory<0, 127> m_127Factory;
|
||||||
|
RangedValueFactory<0, 255> m_255Factory;
|
||||||
|
QStyledItemDelegate m_127Delegate, m_255Delegate;
|
||||||
|
public:
|
||||||
|
explicit SFXTableView(QWidget* parent = Q_NULLPTR);
|
||||||
|
void setModel(QAbstractItemModel* model);
|
||||||
|
void deleteSelection();
|
||||||
|
};
|
||||||
|
|
||||||
|
class SFXPlayerWidget : public QWidget
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
QAction m_playAction;
|
||||||
|
QToolButton m_button;
|
||||||
|
QModelIndex m_index;
|
||||||
|
amuse::GroupId m_groupId;
|
||||||
|
amuse::SFXId m_sfxId;
|
||||||
|
amuse::ObjToken<amuse::Voice> m_vox;
|
||||||
|
public:
|
||||||
|
explicit SFXPlayerWidget(QModelIndex index, amuse::GroupId gid, amuse::SFXId id,
|
||||||
|
QWidget* parent = Q_NULLPTR);
|
||||||
|
~SFXPlayerWidget();
|
||||||
|
amuse::SongId sfxId() const { return m_sfxId; }
|
||||||
|
amuse::Voice* voice() const { return m_vox.get(); }
|
||||||
|
void stopped();
|
||||||
|
void resizeEvent(QResizeEvent* event);
|
||||||
|
void mouseDoubleClickEvent(QMouseEvent* event);
|
||||||
|
void mousePressEvent(QMouseEvent* event);
|
||||||
|
void mouseReleaseEvent(QMouseEvent* event) { event->ignore(); }
|
||||||
|
public slots:
|
||||||
|
void clicked();
|
||||||
|
};
|
||||||
|
|
||||||
|
class SoundGroupEditor : public EditorWidget
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
SFXModel m_sfxs;
|
||||||
|
SFXTableView* m_sfxTable;
|
||||||
|
AddRemoveButtons m_addRemoveButtons;
|
||||||
|
public:
|
||||||
|
explicit SoundGroupEditor(QWidget* parent = Q_NULLPTR);
|
||||||
|
bool loadData(ProjectModel::SoundGroupNode* node);
|
||||||
|
void unloadData();
|
||||||
|
ProjectModel::INode* currentNode() const;
|
||||||
|
void setEditorEnabled(bool en) {}
|
||||||
|
void resizeEvent(QResizeEvent* ev);
|
||||||
|
QTableView* getSFXListView() const { return m_sfxTable; }
|
||||||
|
AmuseItemEditFlags itemEditFlags() const;
|
||||||
|
private slots:
|
||||||
|
void rowsInserted(const QModelIndex &parent, int first, int last);
|
||||||
|
void rowsMoved(const QModelIndex &parent, int start, int end, const QModelIndex &destination, int row);
|
||||||
|
void doAdd();
|
||||||
|
void doSelectionChanged();
|
||||||
|
void sfxDataChanged();
|
||||||
|
void itemDeleteAction();
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif //AMUSE_SOUND_GROUP_EDITOR_HPP
|
||||||
1227
Editor/SoundMacroEditor.cpp
Normal file
190
Editor/SoundMacroEditor.hpp
Normal file
@@ -0,0 +1,190 @@
|
|||||||
|
#ifndef AMUSE_SOUND_MACRO_EDITOR_HPP
|
||||||
|
#define AMUSE_SOUND_MACRO_EDITOR_HPP
|
||||||
|
|
||||||
|
#include "EditorWidget.hpp"
|
||||||
|
#include <QStaticText>
|
||||||
|
#include <QVBoxLayout>
|
||||||
|
#include <QPropertyAnimation>
|
||||||
|
#include <QSplitter>
|
||||||
|
#include <QLabel>
|
||||||
|
#include <QMouseEvent>
|
||||||
|
#include <QSpinBox>
|
||||||
|
#include <QComboBox>
|
||||||
|
#include <QTreeWidget>
|
||||||
|
#include <QPushButton>
|
||||||
|
|
||||||
|
class SoundMacroEditor;
|
||||||
|
class SoundMacroListing;
|
||||||
|
class CatalogueItem;
|
||||||
|
|
||||||
|
class TargetButton : public QPushButton
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
public:
|
||||||
|
explicit TargetButton(QWidget* parent = Q_NULLPTR);
|
||||||
|
void mouseReleaseEvent(QMouseEvent* event) { event->ignore(); }
|
||||||
|
void mouseMoveEvent(QMouseEvent* event) { event->ignore(); }
|
||||||
|
void focusOutEvent(QFocusEvent* event) { event->ignore(); }
|
||||||
|
void keyPressEvent(QKeyEvent* event) { event->ignore(); }
|
||||||
|
};
|
||||||
|
|
||||||
|
class FieldSoundMacroStep : public QWidget
|
||||||
|
{
|
||||||
|
friend class CommandWidget;
|
||||||
|
Q_OBJECT
|
||||||
|
FieldProjectNode* m_macroField;
|
||||||
|
FieldSpinBox m_spinBox;
|
||||||
|
TargetButton m_targetButton;
|
||||||
|
SoundMacroEditor* getEditor() const;
|
||||||
|
SoundMacroListing* getListing() const;
|
||||||
|
signals:
|
||||||
|
void valueChanged(int);
|
||||||
|
public slots:
|
||||||
|
void targetPressed();
|
||||||
|
void updateMacroField();
|
||||||
|
public:
|
||||||
|
explicit FieldSoundMacroStep(FieldProjectNode* macroField = Q_NULLPTR, QWidget* parent = Q_NULLPTR);
|
||||||
|
~FieldSoundMacroStep();
|
||||||
|
void setIndex(int index);
|
||||||
|
void cancel();
|
||||||
|
};
|
||||||
|
|
||||||
|
class CommandWidget : public QWidget
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
friend class SoundMacroListing;
|
||||||
|
QFont m_numberFont;
|
||||||
|
QLabel m_titleLabel;
|
||||||
|
ListingDeleteButton m_deleteButton;
|
||||||
|
QStaticText m_numberText;
|
||||||
|
int m_index = -1;
|
||||||
|
amuse::SoundMacro::ICmd* m_cmd;
|
||||||
|
const amuse::SoundMacro::CmdIntrospection* m_introspection;
|
||||||
|
FieldSoundMacroStep* m_stepField = nullptr;
|
||||||
|
void setIndex(int index);
|
||||||
|
SoundMacroListing* getParent() const;
|
||||||
|
private slots:
|
||||||
|
void boolChanged(int);
|
||||||
|
void numChanged(int);
|
||||||
|
void nodeChanged(int);
|
||||||
|
void deleteClicked();
|
||||||
|
private:
|
||||||
|
CommandWidget(QWidget* parent, amuse::SoundMacro::ICmd* cmd, amuse::SoundMacro::CmdOp op, SoundMacroListing* listing);
|
||||||
|
public:
|
||||||
|
CommandWidget(QWidget* parent, amuse::SoundMacro::ICmd* cmd, SoundMacroListing* listing);
|
||||||
|
CommandWidget(QWidget* parent, amuse::SoundMacro::CmdOp op, SoundMacroListing* listing);
|
||||||
|
void paintEvent(QPaintEvent* event);
|
||||||
|
QString getText() const { return m_titleLabel.text(); }
|
||||||
|
};
|
||||||
|
|
||||||
|
class CommandWidgetContainer : public QWidget
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
friend class SoundMacroListing;
|
||||||
|
CommandWidget* m_commandWidget;
|
||||||
|
QPropertyAnimation* m_animation = nullptr;
|
||||||
|
void animateOpen();
|
||||||
|
void animateClosed();
|
||||||
|
void snapOpen();
|
||||||
|
void snapClosed();
|
||||||
|
private slots:
|
||||||
|
void animationDestroyed();
|
||||||
|
public:
|
||||||
|
template <class..._Args>
|
||||||
|
CommandWidgetContainer(QWidget* parent, _Args&&... args);
|
||||||
|
};
|
||||||
|
|
||||||
|
class SoundMacroListing : public QWidget
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
friend class CommandWidget;
|
||||||
|
friend class SoundMacroEditor;
|
||||||
|
amuse::ObjToken<ProjectModel::SoundMacroNode> m_node;
|
||||||
|
QVBoxLayout* m_layout;
|
||||||
|
QLayoutItem* m_dragItem = nullptr;
|
||||||
|
int m_origIdx = -1;
|
||||||
|
int m_dragOpenIdx = -1;
|
||||||
|
CommandWidgetContainer* m_prevDragOpen = nullptr;
|
||||||
|
int m_autoscrollTimer = -1;
|
||||||
|
int m_autoscrollDelta = 0;
|
||||||
|
QWidget* m_autoscrollSource = nullptr;
|
||||||
|
QMouseEvent m_autoscrollEvent = {{}, {}, {}, {}, {}};
|
||||||
|
void startAutoscroll(QWidget* source, QMouseEvent* event, int delta);
|
||||||
|
void stopAutoscroll();
|
||||||
|
bool beginDrag(CommandWidget* widget);
|
||||||
|
void endDrag();
|
||||||
|
void cancelDrag();
|
||||||
|
void _moveDrag(int hoverIdx, const QPoint& pt, QWidget* source, QMouseEvent* event);
|
||||||
|
void moveDrag(CommandWidget* widget, const QPoint& pt, QWidget* source, QMouseEvent* event);
|
||||||
|
int moveInsertDrag(const QPoint& pt, QWidget* source, QMouseEvent* event);
|
||||||
|
void insertDragout();
|
||||||
|
void insert(amuse::SoundMacro::CmdOp op, const QString& text);
|
||||||
|
void deleteCommand(int index);
|
||||||
|
void reindex();
|
||||||
|
void clear();
|
||||||
|
public:
|
||||||
|
explicit SoundMacroListing(QWidget* parent = Q_NULLPTR);
|
||||||
|
bool loadData(ProjectModel::SoundMacroNode* node);
|
||||||
|
void unloadData();
|
||||||
|
ProjectModel::INode* currentNode() const;
|
||||||
|
void timerEvent(QTimerEvent* event);
|
||||||
|
};
|
||||||
|
|
||||||
|
class CatalogueItem : public QWidget
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
amuse::SoundMacro::CmdOp m_op;
|
||||||
|
QLabel m_iconLab;
|
||||||
|
QLabel m_label;
|
||||||
|
public:
|
||||||
|
explicit CatalogueItem(amuse::SoundMacro::CmdOp op, const QString& name,
|
||||||
|
const QString& doc, QWidget* parent = Q_NULLPTR);
|
||||||
|
explicit CatalogueItem(const CatalogueItem& other, QWidget* parent = Q_NULLPTR);
|
||||||
|
amuse::SoundMacro::CmdOp getCmdOp() const { return m_op; }
|
||||||
|
QString getText() const { return m_label.text(); }
|
||||||
|
};
|
||||||
|
|
||||||
|
class SoundMacroCatalogue : public QTreeWidget
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
public:
|
||||||
|
explicit SoundMacroCatalogue(QWidget* parent = Q_NULLPTR);
|
||||||
|
void mousePressEvent(QMouseEvent* event);
|
||||||
|
void mouseReleaseEvent(QMouseEvent* event);
|
||||||
|
void mouseMoveEvent(QMouseEvent* event);
|
||||||
|
};
|
||||||
|
|
||||||
|
class SoundMacroEditor : public EditorWidget
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
friend class SoundMacroCatalogue;
|
||||||
|
friend class FieldSoundMacroStep;
|
||||||
|
QSplitter* m_splitter;
|
||||||
|
SoundMacroListing* m_listing;
|
||||||
|
SoundMacroCatalogue* m_catalogue;
|
||||||
|
CommandWidget* m_draggedCmd = nullptr;
|
||||||
|
CatalogueItem* m_draggedItem = nullptr;
|
||||||
|
FieldSoundMacroStep* m_targetField = nullptr;
|
||||||
|
QPoint m_draggedPt;
|
||||||
|
int m_dragInsertIdx = -1;
|
||||||
|
void beginCommandDrag(CommandWidget* widget, const QPoint& eventPt, const QPoint& pt);
|
||||||
|
void beginCatalogueDrag(CatalogueItem* item, const QPoint& eventPt, const QPoint& pt);
|
||||||
|
void beginStepTarget(FieldSoundMacroStep* stepField);
|
||||||
|
void endStepTarget();
|
||||||
|
public:
|
||||||
|
explicit SoundMacroEditor(QWidget* parent = Q_NULLPTR);
|
||||||
|
bool loadData(ProjectModel::SoundMacroNode* node);
|
||||||
|
void unloadData();
|
||||||
|
ProjectModel::INode* currentNode() const;
|
||||||
|
|
||||||
|
void mousePressEvent(QMouseEvent* event);
|
||||||
|
void mouseReleaseEvent(QMouseEvent* event);
|
||||||
|
void mouseMoveEvent(QMouseEvent* event);
|
||||||
|
void keyPressEvent(QKeyEvent* event);
|
||||||
|
|
||||||
|
public slots:
|
||||||
|
void catalogueDoubleClicked(QTreeWidgetItem* item, int column);
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
#endif //AMUSE_SOUND_MACRO_EDITOR_HPP
|
||||||
113
Editor/StatusBarWidget.cpp
Normal file
@@ -0,0 +1,113 @@
|
|||||||
|
#include "StatusBarWidget.hpp"
|
||||||
|
|
||||||
|
FXButton::FXButton(QWidget* parent)
|
||||||
|
: QPushButton(parent)
|
||||||
|
{
|
||||||
|
setIcon(QIcon(QStringLiteral(":/icons/IconFX.svg")));
|
||||||
|
setToolTip(tr("Access studio setup window for experimenting with audio effects"));
|
||||||
|
}
|
||||||
|
|
||||||
|
StatusBarWidget::StatusBarWidget(QWidget* parent)
|
||||||
|
: QStatusBar(parent), m_volumeSlider(Qt::Horizontal),
|
||||||
|
m_aSlider(Qt::Horizontal), m_bSlider(Qt::Horizontal)
|
||||||
|
{
|
||||||
|
addWidget(&m_normalMessage);
|
||||||
|
m_killButton.setIcon(QIcon(QStringLiteral(":/icons/IconKill.svg")));
|
||||||
|
m_killButton.setVisible(false);
|
||||||
|
m_killButton.setToolTip(tr("Immediately kill active voices"));
|
||||||
|
m_voiceCount.setVisible(false);
|
||||||
|
m_volumeIcons[0] = QIcon(QStringLiteral(":/icons/IconVolume0.svg"));
|
||||||
|
m_volumeIcons[1] = QIcon(QStringLiteral(":/icons/IconVolume1.svg"));
|
||||||
|
m_volumeIcons[2] = QIcon(QStringLiteral(":/icons/IconVolume2.svg"));
|
||||||
|
m_volumeIcons[3] = QIcon(QStringLiteral(":/icons/IconVolume3.svg"));
|
||||||
|
m_aIcon.setFixedSize(16, 16);
|
||||||
|
m_aIcon.setPixmap(QIcon(QStringLiteral(":/icons/IconA.svg")).pixmap(16, 16));
|
||||||
|
QString aTip = tr("Aux A send level for all voices");
|
||||||
|
m_aIcon.setToolTip(aTip);
|
||||||
|
m_aSlider.setRange(0, 100);
|
||||||
|
m_aSlider.setFixedWidth(100);
|
||||||
|
m_aSlider.setToolTip(aTip);
|
||||||
|
m_bIcon.setFixedSize(16, 16);
|
||||||
|
m_bIcon.setPixmap(QIcon(QStringLiteral(":/icons/IconB.svg")).pixmap(16, 16));
|
||||||
|
QString bTip = tr("Aux B send level for all voices");
|
||||||
|
m_bIcon.setToolTip(bTip);
|
||||||
|
m_bSlider.setRange(0, 100);
|
||||||
|
m_bSlider.setFixedWidth(100);
|
||||||
|
m_bSlider.setToolTip(bTip);
|
||||||
|
m_volumeIcon.setFixedSize(16, 16);
|
||||||
|
m_volumeIcon.setPixmap(m_volumeIcons[0].pixmap(16, 16));
|
||||||
|
QString volTip = tr("Master volume level");
|
||||||
|
m_volumeIcon.setToolTip(volTip);
|
||||||
|
connect(&m_volumeSlider, SIGNAL(valueChanged(int)), this, SLOT(volumeChanged(int)));
|
||||||
|
m_volumeSlider.setRange(0, 100);
|
||||||
|
m_volumeSlider.setFixedWidth(100);
|
||||||
|
m_volumeSlider.setToolTip(volTip);
|
||||||
|
addPermanentWidget(&m_voiceCount);
|
||||||
|
addPermanentWidget(&m_killButton);
|
||||||
|
addPermanentWidget(&m_fxButton);
|
||||||
|
addPermanentWidget(&m_aIcon);
|
||||||
|
addPermanentWidget(&m_aSlider);
|
||||||
|
addPermanentWidget(&m_bIcon);
|
||||||
|
addPermanentWidget(&m_bSlider);
|
||||||
|
addPermanentWidget(&m_volumeIcon);
|
||||||
|
addPermanentWidget(&m_volumeSlider);
|
||||||
|
}
|
||||||
|
|
||||||
|
void StatusBarWidget::setVoiceCount(int voices)
|
||||||
|
{
|
||||||
|
if (voices != m_cachedVoiceCount)
|
||||||
|
{
|
||||||
|
m_voiceCount.setText(QString::number(voices));
|
||||||
|
m_cachedVoiceCount = voices;
|
||||||
|
setKillVisible(voices != 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void StatusBarWidget::volumeChanged(int vol)
|
||||||
|
{
|
||||||
|
int idx = int(std::round(vol * (3.f / 100.f)));
|
||||||
|
if (idx != m_lastVolIdx)
|
||||||
|
{
|
||||||
|
m_lastVolIdx = idx;
|
||||||
|
m_volumeIcon.setPixmap(m_volumeIcons[idx].pixmap(16, 16));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void StatusBarFocus::setMessage(const QString& message)
|
||||||
|
{
|
||||||
|
m_message = message;
|
||||||
|
if (StatusBarWidget* widget = qobject_cast<StatusBarWidget*>(parent()))
|
||||||
|
{
|
||||||
|
if (widget->m_curFocus == this)
|
||||||
|
{
|
||||||
|
if (m_message.isEmpty())
|
||||||
|
widget->clearMessage();
|
||||||
|
else
|
||||||
|
widget->showMessage(m_message);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void StatusBarFocus::enter()
|
||||||
|
{
|
||||||
|
if (StatusBarWidget* widget = qobject_cast<StatusBarWidget*>(parent()))
|
||||||
|
{
|
||||||
|
widget->m_curFocus = this;
|
||||||
|
if (m_message.isEmpty())
|
||||||
|
widget->clearMessage();
|
||||||
|
else
|
||||||
|
widget->showMessage(m_message);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void StatusBarFocus::exit()
|
||||||
|
{
|
||||||
|
if (StatusBarWidget* widget = qobject_cast<StatusBarWidget*>(parent()))
|
||||||
|
{
|
||||||
|
if (widget->m_curFocus == this)
|
||||||
|
{
|
||||||
|
widget->clearMessage();
|
||||||
|
widget->m_curFocus = nullptr;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
77
Editor/StatusBarWidget.hpp
Normal file
@@ -0,0 +1,77 @@
|
|||||||
|
#ifndef AMUSE_STATUSBAR_WIDGET_HPP
|
||||||
|
#define AMUSE_STATUSBAR_WIDGET_HPP
|
||||||
|
|
||||||
|
#include <QStatusBar>
|
||||||
|
#include <QLabel>
|
||||||
|
#include <QPushButton>
|
||||||
|
#include <QSlider>
|
||||||
|
#include <QMouseEvent>
|
||||||
|
#include <cmath>
|
||||||
|
|
||||||
|
class StatusBarFocus;
|
||||||
|
|
||||||
|
class FXButton : public QPushButton
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
public:
|
||||||
|
explicit FXButton(QWidget* parent = Q_NULLPTR);
|
||||||
|
void mouseReleaseEvent(QMouseEvent* event) { event->ignore(); }
|
||||||
|
void mouseMoveEvent(QMouseEvent* event) { event->ignore(); }
|
||||||
|
void focusOutEvent(QFocusEvent* event) { event->ignore(); }
|
||||||
|
void keyPressEvent(QKeyEvent* event) { event->ignore(); }
|
||||||
|
};
|
||||||
|
|
||||||
|
class StatusBarWidget : public QStatusBar
|
||||||
|
{
|
||||||
|
friend class StatusBarFocus;
|
||||||
|
Q_OBJECT
|
||||||
|
QLabel m_normalMessage;
|
||||||
|
QPushButton m_killButton;
|
||||||
|
FXButton m_fxButton;
|
||||||
|
QIcon m_volumeIcons[4];
|
||||||
|
QLabel m_volumeIcon;
|
||||||
|
QSlider m_volumeSlider;
|
||||||
|
QLabel m_aIcon;
|
||||||
|
QSlider m_aSlider;
|
||||||
|
QLabel m_bIcon;
|
||||||
|
QSlider m_bSlider;
|
||||||
|
int m_lastVolIdx = 0;
|
||||||
|
QLabel m_voiceCount;
|
||||||
|
int m_cachedVoiceCount = -1;
|
||||||
|
StatusBarFocus* m_curFocus = nullptr;
|
||||||
|
void setKillVisible(bool vis) { m_killButton.setVisible(vis); m_voiceCount.setVisible(vis); }
|
||||||
|
public:
|
||||||
|
explicit StatusBarWidget(QWidget* parent = Q_NULLPTR);
|
||||||
|
void setNormalMessage(const QString& message) { m_normalMessage.setText(message); }
|
||||||
|
void setVoiceCount(int voices);
|
||||||
|
void connectKillClicked(const QObject* receiver, const char* method)
|
||||||
|
{ connect(&m_killButton, SIGNAL(clicked(bool)), receiver, method); }
|
||||||
|
void connectFXPressed(const QObject* receiver, const char* method)
|
||||||
|
{ connect(&m_fxButton, SIGNAL(pressed()), receiver, method); }
|
||||||
|
void setFXDown(bool down) { m_fxButton.setDown(down); }
|
||||||
|
void connectVolumeSlider(const QObject* receiver, const char* method)
|
||||||
|
{ connect(&m_volumeSlider, SIGNAL(valueChanged(int)), receiver, method); }
|
||||||
|
void connectASlider(const QObject* receiver, const char* method)
|
||||||
|
{ connect(&m_aSlider, SIGNAL(valueChanged(int)), receiver, method); }
|
||||||
|
void connectBSlider(const QObject* receiver, const char* method)
|
||||||
|
{ connect(&m_bSlider, SIGNAL(valueChanged(int)), receiver, method); }
|
||||||
|
void setVolumeValue(int vol) { m_volumeSlider.setValue(vol); }
|
||||||
|
|
||||||
|
private slots:
|
||||||
|
void volumeChanged(int vol);
|
||||||
|
};
|
||||||
|
|
||||||
|
class StatusBarFocus : public QObject
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
QString m_message;
|
||||||
|
public:
|
||||||
|
explicit StatusBarFocus(StatusBarWidget* statusWidget)
|
||||||
|
: QObject(statusWidget) {}
|
||||||
|
~StatusBarFocus() { exit(); }
|
||||||
|
void setMessage(const QString& message);
|
||||||
|
void enter();
|
||||||
|
void exit();
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif //AMUSE_STATUSBAR_WIDGET_HPP
|
||||||
1158
Editor/StudioSetupWidget.cpp
Normal file
205
Editor/StudioSetupWidget.hpp
Normal file
@@ -0,0 +1,205 @@
|
|||||||
|
#ifndef AMUSE_STUDIO_SETUP_WIDGET_HPP
|
||||||
|
#define AMUSE_STUDIO_SETUP_WIDGET_HPP
|
||||||
|
|
||||||
|
#include "EditorWidget.hpp"
|
||||||
|
#include <QWidget>
|
||||||
|
#include <QTreeWidget>
|
||||||
|
#include <QLabel>
|
||||||
|
#include <QVBoxLayout>
|
||||||
|
#include <QLayoutItem>
|
||||||
|
#include <QStaticText>
|
||||||
|
#include <QPropertyAnimation>
|
||||||
|
#include <QScrollArea>
|
||||||
|
#include <QSplitter>
|
||||||
|
#include "amuse/Studio.hpp"
|
||||||
|
|
||||||
|
class EffectListing;
|
||||||
|
|
||||||
|
struct EffectIntrospection
|
||||||
|
{
|
||||||
|
struct Field
|
||||||
|
{
|
||||||
|
enum class Type
|
||||||
|
{
|
||||||
|
Invalid,
|
||||||
|
UInt32,
|
||||||
|
UInt32x8,
|
||||||
|
Float
|
||||||
|
};
|
||||||
|
Type m_tp;
|
||||||
|
std::string_view m_name;
|
||||||
|
float m_min, m_max, m_default;
|
||||||
|
};
|
||||||
|
amuse::EffectType m_tp;
|
||||||
|
std::string_view m_name;
|
||||||
|
std::string_view m_description;
|
||||||
|
Field m_fields[7];
|
||||||
|
};
|
||||||
|
|
||||||
|
class Uint32X8Popup : public QFrame
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
FieldSlider* m_sliders[8];
|
||||||
|
public:
|
||||||
|
explicit Uint32X8Popup(int min, int max, QWidget* parent = Q_NULLPTR);
|
||||||
|
void setValue(int chanIdx, int val);
|
||||||
|
private slots:
|
||||||
|
void doValueChanged(int val);
|
||||||
|
signals:
|
||||||
|
void valueChanged(int chanIdx, int val);
|
||||||
|
};
|
||||||
|
|
||||||
|
class Uint32X8Button : public QPushButton
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
Uint32X8Popup* m_popup;
|
||||||
|
public:
|
||||||
|
explicit Uint32X8Button(int min, int max, QWidget* parent = Q_NULLPTR);
|
||||||
|
void paintEvent(QPaintEvent* event);
|
||||||
|
Uint32X8Popup* popup() const { return m_popup; }
|
||||||
|
QStyleOptionComboBox comboStyleOption() const;
|
||||||
|
private slots:
|
||||||
|
void onPressed();
|
||||||
|
};
|
||||||
|
|
||||||
|
class EffectWidget : public QWidget
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
friend class EffectListing;
|
||||||
|
QFont m_numberFont;
|
||||||
|
QLabel m_titleLabel;
|
||||||
|
ListingDeleteButton m_deleteButton;
|
||||||
|
QStaticText m_numberText;
|
||||||
|
int m_index = -1;
|
||||||
|
amuse::EffectBaseTypeless* m_effect;
|
||||||
|
const EffectIntrospection* m_introspection;
|
||||||
|
void setIndex(int index);
|
||||||
|
private slots:
|
||||||
|
void numChanged(int);
|
||||||
|
void numChanged(double);
|
||||||
|
void chanNumChanged(int, int);
|
||||||
|
void deleteClicked();
|
||||||
|
private:
|
||||||
|
explicit EffectWidget(QWidget* parent, amuse::EffectBaseTypeless* effect, amuse::EffectType type);
|
||||||
|
public:
|
||||||
|
EffectListing* getParent() const;
|
||||||
|
explicit EffectWidget(QWidget* parent, amuse::EffectBaseTypeless* effect);
|
||||||
|
explicit EffectWidget(QWidget* parent, amuse::EffectType op);
|
||||||
|
void paintEvent(QPaintEvent* event);
|
||||||
|
QString getText() const { return m_titleLabel.text(); }
|
||||||
|
};
|
||||||
|
|
||||||
|
class EffectWidgetContainer : public QWidget
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
friend class EffectListing;
|
||||||
|
EffectWidget* m_effectWidget;
|
||||||
|
QPropertyAnimation* m_animation = nullptr;
|
||||||
|
void animateOpen();
|
||||||
|
void animateClosed();
|
||||||
|
void snapOpen();
|
||||||
|
void snapClosed();
|
||||||
|
private slots:
|
||||||
|
void animationDestroyed();
|
||||||
|
public:
|
||||||
|
template <class..._Args>
|
||||||
|
EffectWidgetContainer(QWidget* parent, _Args&&... args);
|
||||||
|
};
|
||||||
|
|
||||||
|
class EffectListing : public QWidget
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
friend class EffectWidget;
|
||||||
|
friend class StudioSetupWidget;
|
||||||
|
amuse::Submix* m_submix = nullptr;
|
||||||
|
QVBoxLayout* m_layout;
|
||||||
|
QLayoutItem* m_dragItem = nullptr;
|
||||||
|
int m_origIdx = -1;
|
||||||
|
int m_dragOpenIdx = -1;
|
||||||
|
EffectWidgetContainer* m_prevDragOpen = nullptr;
|
||||||
|
int m_autoscrollTimer = -1;
|
||||||
|
int m_autoscrollDelta = 0;
|
||||||
|
QWidget* m_autoscrollSource = nullptr;
|
||||||
|
QMouseEvent m_autoscrollEvent = {{}, {}, {}, {}, {}};
|
||||||
|
void startAutoscroll(QWidget* source, QMouseEvent* event, int delta);
|
||||||
|
void stopAutoscroll();
|
||||||
|
bool beginDrag(EffectWidget* widget);
|
||||||
|
void endDrag();
|
||||||
|
void cancelDrag();
|
||||||
|
void _moveDrag(int hoverIdx, const QPoint& pt, QWidget* source, QMouseEvent* event);
|
||||||
|
void moveDrag(EffectWidget* widget, const QPoint& pt, QWidget* source, QMouseEvent* event);
|
||||||
|
int moveInsertDrag(const QPoint& pt, QWidget* source, QMouseEvent* event);
|
||||||
|
void insertDragout();
|
||||||
|
void insert(amuse::EffectType type, const QString& text);
|
||||||
|
void deleteEffect(int index);
|
||||||
|
void reindex();
|
||||||
|
void clear();
|
||||||
|
public:
|
||||||
|
explicit EffectListing(QWidget* parent = Q_NULLPTR);
|
||||||
|
bool loadData(amuse::Submix* submix);
|
||||||
|
void unloadData();
|
||||||
|
void timerEvent(QTimerEvent* event);
|
||||||
|
};
|
||||||
|
|
||||||
|
class EffectCatalogueItem : public QWidget
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
amuse::EffectType m_type;
|
||||||
|
QLabel m_iconLab;
|
||||||
|
QLabel m_label;
|
||||||
|
public:
|
||||||
|
explicit EffectCatalogueItem(amuse::EffectType type, const QString& name,
|
||||||
|
const QString& doc, QWidget* parent = Q_NULLPTR);
|
||||||
|
explicit EffectCatalogueItem(const EffectCatalogueItem& other, QWidget* parent = Q_NULLPTR);
|
||||||
|
amuse::EffectType getType() const { return m_type; }
|
||||||
|
QString getText() const { return m_label.text(); }
|
||||||
|
};
|
||||||
|
|
||||||
|
class EffectCatalogue : public QTreeWidget
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
public:
|
||||||
|
explicit EffectCatalogue(QWidget* parent = Q_NULLPTR);
|
||||||
|
void mousePressEvent(QMouseEvent* event);
|
||||||
|
void mouseReleaseEvent(QMouseEvent* event);
|
||||||
|
void mouseMoveEvent(QMouseEvent* event);
|
||||||
|
};
|
||||||
|
|
||||||
|
class StudioSetupWidget : public QWidget
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
friend class EffectCatalogue;
|
||||||
|
QSplitter* m_splitter;
|
||||||
|
QTabWidget* m_tabs;
|
||||||
|
EffectListing* m_listing[2];
|
||||||
|
EffectCatalogue* m_catalogue;
|
||||||
|
EffectWidget* m_draggedCmd = nullptr;
|
||||||
|
EffectCatalogueItem* m_draggedItem = nullptr;
|
||||||
|
QPoint m_draggedPt;
|
||||||
|
int m_dragInsertIdx = -1;
|
||||||
|
EffectListing* getCurrentListing() const;
|
||||||
|
void beginCommandDrag(EffectWidget* widget, const QPoint& eventPt, const QPoint& pt);
|
||||||
|
void beginCatalogueDrag(EffectCatalogueItem* item, const QPoint& eventPt, const QPoint& pt);
|
||||||
|
public:
|
||||||
|
explicit StudioSetupWidget(QWidget* parent = Q_NULLPTR);
|
||||||
|
bool loadData(amuse::Studio* studio);
|
||||||
|
void unloadData();
|
||||||
|
|
||||||
|
void mousePressEvent(QMouseEvent* event);
|
||||||
|
void mouseReleaseEvent(QMouseEvent* event);
|
||||||
|
void mouseMoveEvent(QMouseEvent* event);
|
||||||
|
void keyPressEvent(QKeyEvent* event);
|
||||||
|
|
||||||
|
void hideEvent(QHideEvent* event);
|
||||||
|
void showEvent(QShowEvent* event);
|
||||||
|
void updateWindowPosition();
|
||||||
|
|
||||||
|
public slots:
|
||||||
|
void catalogueDoubleClicked(QTreeWidgetItem* item, int column);
|
||||||
|
|
||||||
|
signals:
|
||||||
|
void hidden();
|
||||||
|
void shown();
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // AMUSE_STUDIO_SETUP_WIDGET_HPP
|
||||||
122
Editor/main.cpp
Normal file
@@ -0,0 +1,122 @@
|
|||||||
|
#include <cstdint>
|
||||||
|
#include <QApplication>
|
||||||
|
#include <QStyleFactory>
|
||||||
|
#include <QTranslator>
|
||||||
|
#include "MainWindow.hpp"
|
||||||
|
#include "SongGroupEditor.hpp"
|
||||||
|
#include "boo/IApplication.hpp"
|
||||||
|
#include <QResource>
|
||||||
|
#include <QCommandLineParser>
|
||||||
|
#include <logvisor/logvisor.hpp>
|
||||||
|
|
||||||
|
using namespace std::literals;
|
||||||
|
|
||||||
|
#ifdef __APPLE__
|
||||||
|
void MacOSSetDarkAppearance();
|
||||||
|
#endif
|
||||||
|
|
||||||
|
extern "C" const uint8_t MAINICON_QT[];
|
||||||
|
|
||||||
|
static QIcon MakeAppIcon()
|
||||||
|
{
|
||||||
|
QIcon ret;
|
||||||
|
|
||||||
|
const uint8_t* ptr = MAINICON_QT;
|
||||||
|
for (int i = 0; i < 6; ++i)
|
||||||
|
{
|
||||||
|
uint32_t size = *reinterpret_cast<const uint32_t*>(ptr);
|
||||||
|
ptr += 4;
|
||||||
|
|
||||||
|
QPixmap pm;
|
||||||
|
pm.loadFromData(ptr, size);
|
||||||
|
ret.addPixmap(pm);
|
||||||
|
ptr += size;
|
||||||
|
}
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* This is for adapting the get*Name methods */
|
||||||
|
class BooInterface : public boo::IApplication
|
||||||
|
{
|
||||||
|
std::vector<boo::SystemString> m_args;
|
||||||
|
void _deletedWindow(boo::IWindow* window) {}
|
||||||
|
public:
|
||||||
|
EPlatformType getPlatformType() const { return EPlatformType::Qt; }
|
||||||
|
|
||||||
|
int run() { return 0; }
|
||||||
|
boo::SystemStringView getUniqueName() const { return _S("amuse-gui"sv); }
|
||||||
|
boo::SystemStringView getFriendlyName() const { return _S("Amuse"sv); }
|
||||||
|
boo::SystemStringView getProcessName() const { return _S("amuse-gui"sv); }
|
||||||
|
const std::vector<boo::SystemString>& getArgs() const { return m_args; }
|
||||||
|
|
||||||
|
/* Constructors/initializers for sub-objects */
|
||||||
|
std::shared_ptr<boo::IWindow> newWindow(boo::SystemStringView title) { return {}; }
|
||||||
|
};
|
||||||
|
|
||||||
|
MainWindow* g_MainWindow = nullptr;
|
||||||
|
|
||||||
|
int main(int argc, char* argv[])
|
||||||
|
{
|
||||||
|
QApplication::setAttribute(Qt::AA_Use96Dpi);
|
||||||
|
#if (QT_VERSION >= QT_VERSION_CHECK(5, 6, 0))
|
||||||
|
QApplication::setAttribute(Qt::AA_EnableHighDpiScaling);
|
||||||
|
QApplication::setAttribute(Qt::AA_UseHighDpiPixmaps);
|
||||||
|
#endif
|
||||||
|
QApplication::setStyle(new ColoredTabBarStyle(QStyleFactory::create("Fusion")));
|
||||||
|
QApplication a(argc, argv);
|
||||||
|
QApplication::setWindowIcon(MakeAppIcon());
|
||||||
|
|
||||||
|
a.setOrganizationName("AxioDL");
|
||||||
|
a.setApplicationName("Amuse");
|
||||||
|
|
||||||
|
QPalette darkPalette;
|
||||||
|
darkPalette.setColor(QPalette::Window, QColor(53,53,53));
|
||||||
|
darkPalette.setColor(QPalette::WindowText, Qt::white);
|
||||||
|
darkPalette.setColor(QPalette::Base, QColor(42,42,42));
|
||||||
|
darkPalette.setColor(QPalette::Disabled, QPalette::Base, QColor(25,25,25,53));
|
||||||
|
darkPalette.setColor(QPalette::AlternateBase, QColor(53,53,53));
|
||||||
|
darkPalette.setColor(QPalette::ToolTipBase, QColor(42,42,42));
|
||||||
|
darkPalette.setColor(QPalette::ToolTipText, Qt::white);
|
||||||
|
darkPalette.setColor(QPalette::Text, Qt::white);
|
||||||
|
darkPalette.setColor(QPalette::Disabled, QPalette::Text, QColor(255,255,255,120));
|
||||||
|
darkPalette.setColor(QPalette::Disabled, QPalette::Light, QColor(0,0,0,0));
|
||||||
|
darkPalette.setColor(QPalette::Button, QColor(53,53,53));
|
||||||
|
darkPalette.setColor(QPalette::Disabled, QPalette::Button, QColor(53,53,53,53));
|
||||||
|
darkPalette.setColor(QPalette::ButtonText, Qt::white);
|
||||||
|
darkPalette.setColor(QPalette::Disabled, QPalette::ButtonText, QColor(255,255,255,120));
|
||||||
|
darkPalette.setColor(QPalette::BrightText, Qt::red);
|
||||||
|
darkPalette.setColor(QPalette::Link, QColor(42,130,218));
|
||||||
|
darkPalette.setColor(QPalette::Highlight, QColor(42,130,218));
|
||||||
|
darkPalette.setColor(QPalette::Disabled, QPalette::Highlight, QColor(42,130,218,53));
|
||||||
|
darkPalette.setColor(QPalette::HighlightedText, Qt::white);
|
||||||
|
darkPalette.setColor(QPalette::Disabled, QPalette::HighlightedText, QColor(255,255,255,120));
|
||||||
|
a.setPalette(darkPalette);
|
||||||
|
|
||||||
|
#ifdef __APPLE__
|
||||||
|
MacOSSetDarkAppearance();
|
||||||
|
#endif
|
||||||
|
|
||||||
|
logvisor::RegisterConsoleLogger();
|
||||||
|
logvisor::RegisterStandardExceptions();
|
||||||
|
|
||||||
|
BooInterface booApp;
|
||||||
|
boo::APP = &booApp;
|
||||||
|
|
||||||
|
Q_INIT_RESOURCE(translation_res);
|
||||||
|
QTranslator translator;
|
||||||
|
if (translator.load(QLocale(), QLatin1String("lang"), QLatin1String("_"), QLatin1String(":/translations")))
|
||||||
|
a.installTranslator(&translator);
|
||||||
|
|
||||||
|
MainWindow w;
|
||||||
|
g_MainWindow = &w;
|
||||||
|
w.show();
|
||||||
|
|
||||||
|
QCommandLineParser parser;
|
||||||
|
parser.process(a);
|
||||||
|
QStringList args = parser.positionalArguments();
|
||||||
|
if (!args.empty())
|
||||||
|
w.openProject(args.back());
|
||||||
|
|
||||||
|
return a.exec();
|
||||||
|
}
|
||||||
BIN
Editor/platforms/freedesktop/1024x1024/apps/amuse.png
Normal file
|
After Width: | Height: | Size: 216 KiB |
BIN
Editor/platforms/freedesktop/128x128/apps/amuse.png
Normal file
|
After Width: | Height: | Size: 18 KiB |
BIN
Editor/platforms/freedesktop/16x16/apps/amuse.png
Normal file
|
After Width: | Height: | Size: 924 B |
BIN
Editor/platforms/freedesktop/256x256/apps/amuse.png
Normal file
|
After Width: | Height: | Size: 42 KiB |
BIN
Editor/platforms/freedesktop/32x32/apps/amuse.png
Normal file
|
After Width: | Height: | Size: 2.6 KiB |
BIN
Editor/platforms/freedesktop/48x48/apps/amuse.png
Normal file
|
After Width: | Height: | Size: 5.0 KiB |
BIN
Editor/platforms/freedesktop/512x512/apps/amuse.png
Normal file
|
After Width: | Height: | Size: 96 KiB |
BIN
Editor/platforms/freedesktop/64x64/apps/amuse.png
Normal file
|
After Width: | Height: | Size: 7.5 KiB |
18
Editor/platforms/freedesktop/CMakeLists.txt
Normal file
@@ -0,0 +1,18 @@
|
|||||||
|
include_directories(${LIBPNG_INCLUDE_DIR})
|
||||||
|
add_executable(amuse-mkqticon mkqticon.c)
|
||||||
|
target_link_libraries(amuse-mkqticon ${PNG_LIB} ${ZLIB_LIBRARIES})
|
||||||
|
|
||||||
|
macro(declare_qticon_target)
|
||||||
|
add_custom_command(OUTPUT ${amuse_BINARY_DIR}/Editor/platforms/freedesktop/mainicon_qt.bin
|
||||||
|
COMMAND $<TARGET_FILE:amuse-mkqticon>
|
||||||
|
ARGS ${amuse_BINARY_DIR}/Editor/platforms/freedesktop/mainicon_qt.bin
|
||||||
|
DEPENDS
|
||||||
|
${amuse_SOURCE_DIR}/Editor/platforms/freedesktop/128x128/apps/amuse.png
|
||||||
|
${amuse_SOURCE_DIR}/Editor/platforms/freedesktop/64x64/apps/amuse.png
|
||||||
|
${amuse_SOURCE_DIR}/Editor/platforms/freedesktop/48x48/apps/amuse.png
|
||||||
|
${amuse_SOURCE_DIR}/Editor/platforms/freedesktop/32x32/apps/amuse.png
|
||||||
|
${amuse_SOURCE_DIR}/Editor/platforms/freedesktop/16x16/apps/amuse.png
|
||||||
|
WORKING_DIRECTORY ${amuse_SOURCE_DIR}/Editor/platforms/freedesktop
|
||||||
|
COMMENT "Generating mainicon_qt.bin")
|
||||||
|
bintoc(mainicon_qt.cpp ${amuse_BINARY_DIR}/Editor/platforms/freedesktop/mainicon_qt.bin MAINICON_QT)
|
||||||
|
endmacro()
|
||||||
9
Editor/platforms/freedesktop/amuse.desktop
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
[Desktop Entry]
|
||||||
|
Name=Amuse
|
||||||
|
GenericName=MusyX Game Audio Editor
|
||||||
|
Comment=Edit Audio Data of MusyX Sound Groups
|
||||||
|
Exec=amuse-gui
|
||||||
|
Icon=amuse
|
||||||
|
Terminal=false
|
||||||
|
Type=Application
|
||||||
|
Categories=Audio
|
||||||
71
Editor/platforms/freedesktop/mkqticon.c
Normal file
@@ -0,0 +1,71 @@
|
|||||||
|
#include <stdio.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
static const int DIMS[] =
|
||||||
|
{
|
||||||
|
16,
|
||||||
|
32,
|
||||||
|
48,
|
||||||
|
64,
|
||||||
|
128,
|
||||||
|
256,
|
||||||
|
0
|
||||||
|
};
|
||||||
|
|
||||||
|
int main(int argc, char* argv[])
|
||||||
|
{
|
||||||
|
if (argc < 2)
|
||||||
|
{
|
||||||
|
fprintf(stderr, "Usage: makeqticon <out.bin>\n");
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
FILE* ofp = fopen(argv[1], "wb");
|
||||||
|
if (!ofp)
|
||||||
|
{
|
||||||
|
fprintf(stderr, "'%s' is not able to be opened for writing as a regular file\n", argv[1]);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
char command[2048];
|
||||||
|
|
||||||
|
for (const int* d = DIMS ; *d != 0 ; ++d)
|
||||||
|
{
|
||||||
|
printf("Rendering main icon @%dx%d\n", *d, *d);
|
||||||
|
fflush(stdout);
|
||||||
|
|
||||||
|
snprintf(command, 2048, "%dx%d/apps/amuse.png", *d, *d);
|
||||||
|
FILE* fp = fopen(command, "rb");
|
||||||
|
if (!fp)
|
||||||
|
{
|
||||||
|
fprintf(stderr, "unable to open '%s' for reading\n", command);
|
||||||
|
fclose(ofp);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
fseek(fp, 0, SEEK_END);
|
||||||
|
uint32_t size = (uint32_t)ftell(fp);
|
||||||
|
fseek(fp, 0, SEEK_SET);
|
||||||
|
|
||||||
|
fwrite(&size, 1, 4, ofp);
|
||||||
|
|
||||||
|
uint8_t buf[1024];
|
||||||
|
while (size > 0)
|
||||||
|
{
|
||||||
|
long thisSize = size;
|
||||||
|
if (thisSize > 1024)
|
||||||
|
thisSize = 1024;
|
||||||
|
|
||||||
|
fread(buf, 1, (size_t)thisSize, fp);
|
||||||
|
fwrite(buf, 1, (size_t)thisSize, ofp);
|
||||||
|
size -= thisSize;
|
||||||
|
}
|
||||||
|
|
||||||
|
fclose(fp);
|
||||||
|
}
|
||||||
|
|
||||||
|
fclose(ofp);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
32
Editor/platforms/mac/Info.plist
Normal file
@@ -0,0 +1,32 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||||
|
<plist version="1.0">
|
||||||
|
<dict>
|
||||||
|
<key>CFBundleExecutable</key>
|
||||||
|
<string>amuse-gui</string>
|
||||||
|
<key>CFBundleGetInfoString</key>
|
||||||
|
<string>Version BETA</string>
|
||||||
|
<key>CFBundleShortVersionString</key>
|
||||||
|
<string>BETA</string>
|
||||||
|
<key>NSHumanReadableCopyright</key>
|
||||||
|
<string>2015-2018 Antidote / Jackoalan</string>
|
||||||
|
<key>CFBundleIconFile</key>
|
||||||
|
<string>mainicon.icns</string>
|
||||||
|
<key>CFBundleIdentifier</key>
|
||||||
|
<string>com.axiodl.Amuse</string>
|
||||||
|
<key>CFBundleInfoDictionaryVersion</key>
|
||||||
|
<string>6.0</string>
|
||||||
|
<key>CFBundleName</key>
|
||||||
|
<string>Amuse</string>
|
||||||
|
<key>CFBundleVersion</key>
|
||||||
|
<string>BETA</string>
|
||||||
|
<key>CFBundlePackageType</key>
|
||||||
|
<string>APPL</string>
|
||||||
|
<key>CFBundleSignature</key>
|
||||||
|
<string>????</string>
|
||||||
|
<key>NSPrincipalClass</key>
|
||||||
|
<string>NSApplication</string>
|
||||||
|
<key>NSHighResolutionCapable</key>
|
||||||
|
<true/>
|
||||||
|
</dict>
|
||||||
|
</plist>
|
||||||
BIN
Editor/platforms/mac/mainicon.icns
Normal file
23
Editor/platforms/win/amuse-gui.manifest
Normal file
@@ -0,0 +1,23 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
|
||||||
|
<assembly manifestVersion="1.0" xmlns="urn:schemas-microsoft-com:asm.v1" xmlns:asmv3="urn:schemas-microsoft-com:asm.v3">
|
||||||
|
<description>Amuse</description>
|
||||||
|
<compatibility xmlns="urn:schemas-microsoft-com:compatibility.v1">
|
||||||
|
<application>
|
||||||
|
<!-- Windows 10 -->
|
||||||
|
<supportedOS Id="{8e0f7a12-bfb3-4fe8-b9a5-48fd50a15a9a}"/>
|
||||||
|
<!-- Windows 8.1 -->
|
||||||
|
<supportedOS Id="{1f676c76-80e1-4239-95bb-83d0f6d0da78}"/>
|
||||||
|
<!-- Windows Vista -->
|
||||||
|
<supportedOS Id="{e2011457-1546-43c5-a5fe-008deee3d3f0}"/>
|
||||||
|
<!-- Windows 7 -->
|
||||||
|
<supportedOS Id="{35138b9a-5d96-4fbd-8e2d-a2440225f93a}"/>
|
||||||
|
<!-- Windows 8 -->
|
||||||
|
<supportedOS Id="{4a2f28e3-53b9-4441-ba9c-d69d4a4a6e38}"/>
|
||||||
|
</application>
|
||||||
|
</compatibility>
|
||||||
|
<asmv3:application>
|
||||||
|
<asmv3:windowsSettings xmlns="http://schemas.microsoft.com/SMI/2005/WindowsSettings">
|
||||||
|
<dpiAware>true/PM</dpiAware>
|
||||||
|
</asmv3:windowsSettings>
|
||||||
|
</asmv3:application>
|
||||||
|
</assembly>
|
||||||
33
Editor/platforms/win/amuse-gui.rc
Normal file
@@ -0,0 +1,33 @@
|
|||||||
|
#include "winver.h"
|
||||||
|
#define IDI_ICON1 101
|
||||||
|
|
||||||
|
IDI_ICON1 ICON DISCARDABLE "mainicon.ico"
|
||||||
|
|
||||||
|
VS_VERSION_INFO VERSIONINFO
|
||||||
|
FILEVERSION 1,0,0,0
|
||||||
|
PRODUCTVERSION 1,0,0,0
|
||||||
|
FILEFLAGS 0x0L
|
||||||
|
FILEFLAGSMASK 0x3fL
|
||||||
|
FILEOS 0x00040004L
|
||||||
|
FILETYPE 0x1L
|
||||||
|
FILESUBTYPE 0x0L
|
||||||
|
BEGIN
|
||||||
|
BLOCK "StringFileInfo"
|
||||||
|
BEGIN
|
||||||
|
BLOCK "000004b0"
|
||||||
|
BEGIN
|
||||||
|
VALUE "CompanyName", "Antidote / Jackoalan"
|
||||||
|
VALUE "FileDescription", "Amuse"
|
||||||
|
VALUE "FileVersion", "BETA"
|
||||||
|
VALUE "LegalCopyright", "Copyright (C) 2015-2018 Antidote / Jackoalan"
|
||||||
|
VALUE "InternalName", "amuse"
|
||||||
|
VALUE "OriginalFilename", "amuse-gui.exe"
|
||||||
|
VALUE "ProductName", "Amuse"
|
||||||
|
VALUE "ProductVersion", "BETA"
|
||||||
|
END
|
||||||
|
END
|
||||||
|
BLOCK "VarFileInfo"
|
||||||
|
BEGIN
|
||||||
|
VALUE "Translation", 0x0, 1200
|
||||||
|
END
|
||||||
|
END
|
||||||
BIN
Editor/platforms/win/mainicon.ico
Normal file
|
After Width: | Height: | Size: 118 KiB |
579
Editor/resources/FaceGrey.svg
Normal file
@@ -0,0 +1,579 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||||
|
<!-- Created with Inkscape (http://www.inkscape.org/) -->
|
||||||
|
|
||||||
|
<svg
|
||||||
|
xmlns:dc="http://purl.org/dc/elements/1.1/"
|
||||||
|
xmlns:cc="http://creativecommons.org/ns#"
|
||||||
|
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
|
||||||
|
xmlns:svg="http://www.w3.org/2000/svg"
|
||||||
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
|
xmlns:xlink="http://www.w3.org/1999/xlink"
|
||||||
|
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||||
|
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||||
|
width="247.54231"
|
||||||
|
height="247.54233"
|
||||||
|
viewBox="0 0 261.98227 261.98229"
|
||||||
|
id="svg2"
|
||||||
|
version="1.1"
|
||||||
|
inkscape:version="0.92.2 2405546, 2018-03-11"
|
||||||
|
sodipodi:docname="FaceGrey.svg"
|
||||||
|
inkscape:export-filename="/Users/jacko/Desktop/amuse-logo/face1024.png"
|
||||||
|
inkscape:export-xdpi="96.000008"
|
||||||
|
inkscape:export-ydpi="96.000008">
|
||||||
|
<defs
|
||||||
|
id="defs4">
|
||||||
|
<linearGradient
|
||||||
|
id="linearGradient4345">
|
||||||
|
<stop
|
||||||
|
id="stop4353"
|
||||||
|
offset="0"
|
||||||
|
style="stop-color:#858585;stop-opacity:1;" />
|
||||||
|
<stop
|
||||||
|
style="stop-color:#4f4f4f;stop-opacity:1;"
|
||||||
|
offset="0.27903292"
|
||||||
|
id="stop4351" />
|
||||||
|
<stop
|
||||||
|
id="stop4349"
|
||||||
|
offset="0.56446373"
|
||||||
|
style="stop-color:#606060;stop-opacity:1;" />
|
||||||
|
<stop
|
||||||
|
id="stop4347"
|
||||||
|
offset="1"
|
||||||
|
style="stop-color:#484848;stop-opacity:1;" />
|
||||||
|
</linearGradient>
|
||||||
|
<linearGradient
|
||||||
|
id="linearGradient4315">
|
||||||
|
<stop
|
||||||
|
id="stop4323"
|
||||||
|
offset="0"
|
||||||
|
style="stop-color:#414141;stop-opacity:1;" />
|
||||||
|
<stop
|
||||||
|
id="stop4321"
|
||||||
|
offset="0.43553627"
|
||||||
|
style="stop-color:#4e4e4e;stop-opacity:1;" />
|
||||||
|
<stop
|
||||||
|
style="stop-color:#7c7c7c;stop-opacity:1;"
|
||||||
|
offset="0.72096705"
|
||||||
|
id="stop4319" />
|
||||||
|
<stop
|
||||||
|
id="stop4317"
|
||||||
|
offset="1"
|
||||||
|
style="stop-color:#b1b1b1;stop-opacity:1;" />
|
||||||
|
</linearGradient>
|
||||||
|
<linearGradient
|
||||||
|
id="linearGradient4346">
|
||||||
|
<stop
|
||||||
|
style="stop-color:#cdcdcd;stop-opacity:1;"
|
||||||
|
offset="0"
|
||||||
|
id="stop4348" />
|
||||||
|
<stop
|
||||||
|
id="stop4350"
|
||||||
|
offset="0.5"
|
||||||
|
style="stop-color:#8f8f8f;stop-opacity:1;" />
|
||||||
|
<stop
|
||||||
|
style="stop-color:#4e4e4e;stop-opacity:1;"
|
||||||
|
offset="0.50999999"
|
||||||
|
id="stop4352" />
|
||||||
|
<stop
|
||||||
|
style="stop-color:#414141;stop-opacity:1;"
|
||||||
|
offset="1"
|
||||||
|
id="stop4354" />
|
||||||
|
</linearGradient>
|
||||||
|
<linearGradient
|
||||||
|
id="linearGradient4287">
|
||||||
|
<stop
|
||||||
|
id="stop4336"
|
||||||
|
offset="0"
|
||||||
|
style="stop-color:#ffffff;stop-opacity:1;" />
|
||||||
|
<stop
|
||||||
|
style="stop-color:#b9b9b9;stop-opacity:1;"
|
||||||
|
offset="0.5"
|
||||||
|
id="stop4338" />
|
||||||
|
<stop
|
||||||
|
id="stop4340"
|
||||||
|
offset="0.50999999"
|
||||||
|
style="stop-color:#7b7b7b;stop-opacity:1;" />
|
||||||
|
<stop
|
||||||
|
id="stop4342"
|
||||||
|
offset="1"
|
||||||
|
style="stop-color:#888888;stop-opacity:1;" />
|
||||||
|
</linearGradient>
|
||||||
|
<linearGradient
|
||||||
|
inkscape:collect="always"
|
||||||
|
id="linearGradient4369">
|
||||||
|
<stop
|
||||||
|
style="stop-color:#000000;stop-opacity:1;"
|
||||||
|
offset="0"
|
||||||
|
id="stop4371" />
|
||||||
|
<stop
|
||||||
|
style="stop-color:#000000;stop-opacity:0;"
|
||||||
|
offset="1"
|
||||||
|
id="stop4373" />
|
||||||
|
</linearGradient>
|
||||||
|
<linearGradient
|
||||||
|
inkscape:collect="always"
|
||||||
|
xlink:href="#linearGradient4287"
|
||||||
|
id="linearGradient4354"
|
||||||
|
gradientUnits="userSpaceOnUse"
|
||||||
|
x1="66.356667"
|
||||||
|
y1="-135.465"
|
||||||
|
x2="204.57664"
|
||||||
|
y2="-135.465" />
|
||||||
|
<linearGradient
|
||||||
|
inkscape:collect="always"
|
||||||
|
xlink:href="#linearGradient4287"
|
||||||
|
id="linearGradient4356"
|
||||||
|
gradientUnits="userSpaceOnUse"
|
||||||
|
x1="66.356667"
|
||||||
|
y1="-135.465"
|
||||||
|
x2="204.57664"
|
||||||
|
y2="-135.465" />
|
||||||
|
<linearGradient
|
||||||
|
inkscape:collect="always"
|
||||||
|
xlink:href="#linearGradient4287"
|
||||||
|
id="linearGradient4358"
|
||||||
|
gradientUnits="userSpaceOnUse"
|
||||||
|
x1="66.356667"
|
||||||
|
y1="-135.465"
|
||||||
|
x2="204.57664"
|
||||||
|
y2="-135.465" />
|
||||||
|
<linearGradient
|
||||||
|
inkscape:collect="always"
|
||||||
|
xlink:href="#linearGradient4287"
|
||||||
|
id="linearGradient4375"
|
||||||
|
x1="5.4296875"
|
||||||
|
y1="135.4668"
|
||||||
|
x2="265.5"
|
||||||
|
y2="135.4668"
|
||||||
|
gradientUnits="userSpaceOnUse" />
|
||||||
|
<linearGradient
|
||||||
|
inkscape:collect="always"
|
||||||
|
xlink:href="#linearGradient4369"
|
||||||
|
id="linearGradient4377"
|
||||||
|
gradientUnits="userSpaceOnUse"
|
||||||
|
x1="5.4296875"
|
||||||
|
y1="135.4668"
|
||||||
|
x2="265.5"
|
||||||
|
y2="135.4668"
|
||||||
|
gradientTransform="matrix(0,3.7795276,-3.7795276,0,0.00629291,0)" />
|
||||||
|
<linearGradient
|
||||||
|
inkscape:collect="always"
|
||||||
|
xlink:href="#linearGradient4287"
|
||||||
|
id="linearGradient4380"
|
||||||
|
gradientUnits="userSpaceOnUse"
|
||||||
|
gradientTransform="matrix(0,3.7795276,-3.7795276,0,0.00629291,0)"
|
||||||
|
x1="5.4296875"
|
||||||
|
y1="135.4668"
|
||||||
|
x2="265.5"
|
||||||
|
y2="135.4668" />
|
||||||
|
<linearGradient
|
||||||
|
inkscape:collect="always"
|
||||||
|
xlink:href="#linearGradient4369"
|
||||||
|
id="linearGradient4186"
|
||||||
|
x1="5.4296875"
|
||||||
|
y1="135.4668"
|
||||||
|
x2="265.5"
|
||||||
|
y2="135.4668"
|
||||||
|
gradientUnits="userSpaceOnUse" />
|
||||||
|
<linearGradient
|
||||||
|
inkscape:collect="always"
|
||||||
|
xlink:href="#linearGradient4345"
|
||||||
|
id="linearGradient4332"
|
||||||
|
x1="61.876694"
|
||||||
|
y1="33.663357"
|
||||||
|
x2="20.055458"
|
||||||
|
y2="244.05054"
|
||||||
|
gradientUnits="userSpaceOnUse" />
|
||||||
|
<linearGradient
|
||||||
|
inkscape:collect="always"
|
||||||
|
xlink:href="#linearGradient4345"
|
||||||
|
id="linearGradient4184"
|
||||||
|
gradientUnits="userSpaceOnUse"
|
||||||
|
x1="5.9291153"
|
||||||
|
y1="-7.2909441"
|
||||||
|
x2="5.9291153"
|
||||||
|
y2="1029.2085" />
|
||||||
|
<linearGradient
|
||||||
|
inkscape:collect="always"
|
||||||
|
xlink:href="#linearGradient4315"
|
||||||
|
id="linearGradient4187"
|
||||||
|
gradientUnits="userSpaceOnUse"
|
||||||
|
x1="-2.135401"
|
||||||
|
y1="373.35422"
|
||||||
|
x2="-2.135401"
|
||||||
|
y2="640.49878" />
|
||||||
|
<linearGradient
|
||||||
|
inkscape:collect="always"
|
||||||
|
xlink:href="#linearGradient4287"
|
||||||
|
id="linearGradient4359"
|
||||||
|
gradientUnits="userSpaceOnUse"
|
||||||
|
x1="5.4296875"
|
||||||
|
y1="135.4668"
|
||||||
|
x2="265.5"
|
||||||
|
y2="135.4668" />
|
||||||
|
<linearGradient
|
||||||
|
inkscape:collect="always"
|
||||||
|
xlink:href="#linearGradient4287"
|
||||||
|
id="linearGradient4380-5"
|
||||||
|
gradientUnits="userSpaceOnUse"
|
||||||
|
gradientTransform="matrix(0,1.0065636,-1.0065636,0,-0.88913176,-0.88914365)"
|
||||||
|
x1="5.4296875"
|
||||||
|
y1="135.4668"
|
||||||
|
x2="265.5"
|
||||||
|
y2="135.4668" />
|
||||||
|
<linearGradient
|
||||||
|
inkscape:collect="always"
|
||||||
|
xlink:href="#linearGradient4287"
|
||||||
|
id="linearGradient4526"
|
||||||
|
gradientUnits="userSpaceOnUse"
|
||||||
|
gradientTransform="matrix(0,3.7795276,-3.7795276,0,0.00629291,0)"
|
||||||
|
x1="5.4296875"
|
||||||
|
y1="135.4668"
|
||||||
|
x2="265.5"
|
||||||
|
y2="135.4668" />
|
||||||
|
<linearGradient
|
||||||
|
inkscape:collect="always"
|
||||||
|
xlink:href="#linearGradient4287"
|
||||||
|
id="linearGradient4528"
|
||||||
|
gradientUnits="userSpaceOnUse"
|
||||||
|
x1="5.4296875"
|
||||||
|
y1="135.4668"
|
||||||
|
x2="265.5"
|
||||||
|
y2="135.4668" />
|
||||||
|
<linearGradient
|
||||||
|
inkscape:collect="always"
|
||||||
|
xlink:href="#linearGradient4287"
|
||||||
|
id="linearGradient4530"
|
||||||
|
gradientUnits="userSpaceOnUse"
|
||||||
|
x1="5.4296875"
|
||||||
|
y1="135.4668"
|
||||||
|
x2="265.5"
|
||||||
|
y2="135.4668" />
|
||||||
|
<linearGradient
|
||||||
|
inkscape:collect="always"
|
||||||
|
xlink:href="#linearGradient4287"
|
||||||
|
id="linearGradient4532"
|
||||||
|
gradientUnits="userSpaceOnUse"
|
||||||
|
x1="66.356667"
|
||||||
|
y1="-135.465"
|
||||||
|
x2="204.57664"
|
||||||
|
y2="-135.465" />
|
||||||
|
<linearGradient
|
||||||
|
inkscape:collect="always"
|
||||||
|
xlink:href="#linearGradient4287"
|
||||||
|
id="linearGradient4534"
|
||||||
|
gradientUnits="userSpaceOnUse"
|
||||||
|
x1="66.356667"
|
||||||
|
y1="-135.465"
|
||||||
|
x2="204.57664"
|
||||||
|
y2="-135.465" />
|
||||||
|
<linearGradient
|
||||||
|
inkscape:collect="always"
|
||||||
|
xlink:href="#linearGradient4287"
|
||||||
|
id="linearGradient4536"
|
||||||
|
gradientUnits="userSpaceOnUse"
|
||||||
|
x1="66.356667"
|
||||||
|
y1="-135.465"
|
||||||
|
x2="204.57664"
|
||||||
|
y2="-135.465" />
|
||||||
|
<linearGradient
|
||||||
|
inkscape:collect="always"
|
||||||
|
xlink:href="#linearGradient4287"
|
||||||
|
id="linearGradient4552"
|
||||||
|
gradientUnits="userSpaceOnUse"
|
||||||
|
gradientTransform="matrix(0,3.7795276,-3.7795276,0,0.00629291,0)"
|
||||||
|
x1="5.4296875"
|
||||||
|
y1="135.4668"
|
||||||
|
x2="265.5"
|
||||||
|
y2="135.4668" />
|
||||||
|
<linearGradient
|
||||||
|
inkscape:collect="always"
|
||||||
|
xlink:href="#linearGradient4287"
|
||||||
|
id="linearGradient4554"
|
||||||
|
gradientUnits="userSpaceOnUse"
|
||||||
|
x1="5.4296875"
|
||||||
|
y1="135.4668"
|
||||||
|
x2="265.5"
|
||||||
|
y2="135.4668" />
|
||||||
|
<linearGradient
|
||||||
|
inkscape:collect="always"
|
||||||
|
xlink:href="#linearGradient4287"
|
||||||
|
id="linearGradient4556"
|
||||||
|
gradientUnits="userSpaceOnUse"
|
||||||
|
x1="5.4296875"
|
||||||
|
y1="135.4668"
|
||||||
|
x2="265.5"
|
||||||
|
y2="135.4668" />
|
||||||
|
<linearGradient
|
||||||
|
inkscape:collect="always"
|
||||||
|
xlink:href="#linearGradient4287"
|
||||||
|
id="linearGradient4558"
|
||||||
|
gradientUnits="userSpaceOnUse"
|
||||||
|
x1="66.356667"
|
||||||
|
y1="-135.465"
|
||||||
|
x2="204.57664"
|
||||||
|
y2="-135.465" />
|
||||||
|
<linearGradient
|
||||||
|
inkscape:collect="always"
|
||||||
|
xlink:href="#linearGradient4287"
|
||||||
|
id="linearGradient4560"
|
||||||
|
gradientUnits="userSpaceOnUse"
|
||||||
|
x1="66.356667"
|
||||||
|
y1="-135.465"
|
||||||
|
x2="204.57664"
|
||||||
|
y2="-135.465" />
|
||||||
|
<linearGradient
|
||||||
|
inkscape:collect="always"
|
||||||
|
xlink:href="#linearGradient4287"
|
||||||
|
id="linearGradient4562"
|
||||||
|
gradientUnits="userSpaceOnUse"
|
||||||
|
x1="66.356667"
|
||||||
|
y1="-135.465"
|
||||||
|
x2="204.57664"
|
||||||
|
y2="-135.465" />
|
||||||
|
</defs>
|
||||||
|
<sodipodi:namedview
|
||||||
|
id="base"
|
||||||
|
pagecolor="#3a3a3a"
|
||||||
|
bordercolor="#666666"
|
||||||
|
borderopacity="1.0"
|
||||||
|
inkscape:pageopacity="0.00392157"
|
||||||
|
inkscape:pageshadow="2"
|
||||||
|
inkscape:zoom="2.5293854"
|
||||||
|
inkscape:cx="57.159723"
|
||||||
|
inkscape:cy="115.45029"
|
||||||
|
inkscape:document-units="mm"
|
||||||
|
inkscape:current-layer="layer3"
|
||||||
|
showgrid="false"
|
||||||
|
units="px"
|
||||||
|
inkscape:window-width="1555"
|
||||||
|
inkscape:window-height="1280"
|
||||||
|
inkscape:window-x="1890"
|
||||||
|
inkscape:window-y="286"
|
||||||
|
inkscape:window-maximized="0"
|
||||||
|
scale-x="4"
|
||||||
|
fit-margin-top="0"
|
||||||
|
fit-margin-left="0"
|
||||||
|
fit-margin-right="0"
|
||||||
|
fit-margin-bottom="0" />
|
||||||
|
<metadata
|
||||||
|
id="metadata7">
|
||||||
|
<rdf:RDF>
|
||||||
|
<cc:Work
|
||||||
|
rdf:about="">
|
||||||
|
<dc:format>image/svg+xml</dc:format>
|
||||||
|
<dc:type
|
||||||
|
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
|
||||||
|
<dc:title></dc:title>
|
||||||
|
</cc:Work>
|
||||||
|
</rdf:RDF>
|
||||||
|
</metadata>
|
||||||
|
<g
|
||||||
|
inkscape:label="source"
|
||||||
|
inkscape:groupmode="layer"
|
||||||
|
id="layer1"
|
||||||
|
transform="translate(-4.3711946,-30.440026)"
|
||||||
|
style="display:none"
|
||||||
|
sodipodi:insensitive="true">
|
||||||
|
<text
|
||||||
|
xml:space="preserve"
|
||||||
|
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;line-height:0%;font-family:'Fira Code';-inkscape-font-specification:'Fira Code';letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.26458332px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
|
||||||
|
x="53.794159"
|
||||||
|
y="-74.699028"
|
||||||
|
id="text4141"
|
||||||
|
transform="rotate(90)"><tspan
|
||||||
|
sodipodi:role="line"
|
||||||
|
id="tspan4143"
|
||||||
|
x="53.794159"
|
||||||
|
y="-74.699028"
|
||||||
|
style="font-size:176.3888855px;line-height:1.25;letter-spacing:-26.45833206px;stroke-width:0.26458332px">:D</tspan></text>
|
||||||
|
<circle
|
||||||
|
style="opacity:1;fill:none;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:8.24636078;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
|
||||||
|
id="path4147"
|
||||||
|
cx="135.465"
|
||||||
|
cy="161.53331"
|
||||||
|
r="92.200752" />
|
||||||
|
<circle
|
||||||
|
r="107.47308"
|
||||||
|
cy="161.53331"
|
||||||
|
cx="135.465"
|
||||||
|
id="circle4173"
|
||||||
|
style="opacity:1;fill:none;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:4.88776207;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" />
|
||||||
|
<circle
|
||||||
|
style="opacity:1;fill:none;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:2.47896814;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
|
||||||
|
id="circle4175"
|
||||||
|
cx="135.465"
|
||||||
|
cy="161.53331"
|
||||||
|
r="119.55315" />
|
||||||
|
<circle
|
||||||
|
r="129.68999"
|
||||||
|
cy="161.53331"
|
||||||
|
cx="135.465"
|
||||||
|
id="circle4177"
|
||||||
|
style="opacity:1;fill:none;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:0.68900001;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" />
|
||||||
|
</g>
|
||||||
|
<g
|
||||||
|
inkscape:groupmode="layer"
|
||||||
|
id="layer2"
|
||||||
|
inkscape:label="path"
|
||||||
|
style="display:inline;opacity:0.76700003"
|
||||||
|
sodipodi:insensitive="true"
|
||||||
|
transform="translate(-4.3711946,-4.3733763)">
|
||||||
|
<g
|
||||||
|
id="g4360"
|
||||||
|
style="fill:url(#linearGradient4375);fill-opacity:1"
|
||||||
|
transform="matrix(1.0065636,0,0,1.0065636,-0.88913164,-0.88914604)">
|
||||||
|
<g
|
||||||
|
id="text4141-2"
|
||||||
|
aria-label=":D"
|
||||||
|
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:10.58333302px;line-height:125%;font-family:'Fira Code';-inkscape-font-specification:'Fira Code';letter-spacing:0px;word-spacing:0px;fill:url(#linearGradient4359);fill-opacity:1;stroke:none;stroke-width:0.26458332px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
|
||||||
|
transform="rotate(90)">
|
||||||
|
<path
|
||||||
|
style="font-size:176.3888855px;letter-spacing:-26.45833206px;fill:url(#linearGradient4380);fill-opacity:1;stroke-width:0.99999994px"
|
||||||
|
d="M 512,147.94141 C 311.12038,147.94141 147.93945,311.12036 147.93945,512 147.93945,712.87962 311.12038,876.06055 512,876.06055 712.87966,876.06055 876.05859,712.87962 876.05859,512 876.05859,311.12036 712.87966,147.94141 512,147.94141 Z m 0,31.16601 c 184.03556,0 332.89258,148.85702 332.89258,332.89258 0,184.03552 -148.85702,332.89453 -332.89258,332.89453 -184.03553,0 -332.89453,-148.85901 -332.89453,-332.89453 0,-184.03556 148.859,-332.89258 332.89453,-332.89258 z m -129.66602,71.68946 c -15.55555,0 -28.44574,5.11176 -38.66796,15.33398 -10.22223,10.22222 -15.33204,22.88889 -15.33204,38 0,15.55555 5.10981,28.44379 15.33204,38.66602 10.22222,10.22222 23.11241,15.33398 38.66796,15.33398 15.11111,0 27.77777,-5.11176 38,-15.33398 10.66666,-10.22223 16,-23.11047 16,-38.66602 0,-15.11111 -5.33334,-27.77778 -16,-38 -10.66668,-10.22222 -23.33334,-15.33398 -38,-15.33398 z m 240.66602,0 c -15.11111,0 -27.99933,5.11176 -38.66602,15.33398 -10.66665,10.22222 -16,22.88889 -16,38 0,15.55555 5.33335,28.44379 16,38.66602 10.66669,10.22222 23.55491,15.33398 38.66602,15.33398 14.66666,0 27.11175,-5.11176 37.33398,-15.33398 10.66666,-10.22223 16,-23.11047 16,-38.66602 0,-15.11111 -5.33334,-27.77778 -16,-38 C 650.11175,255.90864 637.66666,250.79688 623,250.79688 Z M 282.33398,459.86914 v 105.33398 c 0,58.66666 16.88824,108 50.66602,148 33.77778,40.00001 94.22288,60 181.33398,60 86.66666,0 146.22157,-19.77843 178.66602,-59.33398 32.44445,-39.55555 48.66602,-91.55555 48.66602,-156 v -98 z m 46.66602,58 h 365.33398 v 54 c 0,25.77779 -4.44509,48.66797 -13.33398,68.66797 -8.44445,20 -25.99936,36.66668 -52.66602,50 -26.22221,13.77779 -64.22221,20.66601 -114,20.66601 -68.88889,0 -117.11242,-13.33331 -144.66796,-40 C 342.5549,644.98091 329,612.09266 329,572.53711 Z"
|
||||||
|
transform="matrix(0,-0.26458333,0.26458333,0,0,0.001665)"
|
||||||
|
id="path4247"
|
||||||
|
inkscape:connector-curvature="0"
|
||||||
|
sodipodi:nodetypes="ssssssssssssssscsssssssscscscsssssccccsccscsc" />
|
||||||
|
</g>
|
||||||
|
</g>
|
||||||
|
<g
|
||||||
|
id="g4348"
|
||||||
|
aria-label=":D"
|
||||||
|
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:10.58333302px;line-height:125%;font-family:'Fira Code';-inkscape-font-specification:'Fira Code';letter-spacing:0px;word-spacing:0px;display:none;fill:url(#linearGradient4358);fill-opacity:1;stroke:none;stroke-width:0.26458332px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
|
||||||
|
transform="rotate(90,-110.10081,-119.91599)">
|
||||||
|
<path
|
||||||
|
id="path4350"
|
||||||
|
style="font-size:176.3888855px;letter-spacing:-26.45833206px;fill:url(#linearGradient4354);fill-opacity:1;stroke-width:0.26458332px"
|
||||||
|
d="m 66.356665,-164.83375 q 0,-5.82083 4.056944,-9.87778 4.056945,-4.23333 10.054167,-4.23333 6.173611,0 10.230555,4.23333 4.056944,4.05695 4.056944,9.87778 0,5.99722 -4.056944,10.23056 -4.056944,4.23333 -10.230555,4.23333 -5.997222,0 -10.054167,-4.23333 -4.056944,-4.23334 -4.056944,-10.23056 z m 0,63.67639 q 0,-5.82083 4.056944,-10.05417 4.056945,-4.23333 10.054167,-4.23333 6.173611,0 10.230555,4.23333 4.056944,4.05695 4.056944,10.05417 0,6.17361 -4.056944,10.230555 -4.056944,4.056944 -10.230555,4.056944 -5.997222,0 -10.054167,-4.056944 -4.056944,-4.056945 -4.056944,-10.230555 z"
|
||||||
|
inkscape:connector-curvature="0" />
|
||||||
|
<path
|
||||||
|
id="path4352"
|
||||||
|
style="font-size:176.3888855px;letter-spacing:-26.45833206px;fill:url(#linearGradient4356);fill-opacity:1;stroke-width:0.26458332px"
|
||||||
|
d="m 204.57664,-136.08236 q 0,34.57222 -15.875,47.977777 -15.875,13.405555 -39.15833,13.405555 H 121.67387 V -196.23097 h 25.92916 q 25.57639,0 41.275,12.87639 15.69861,12.87639 15.69861,47.27222 z m -16.40416,0 q 0,-19.75556 -5.46806,-30.1625 -5.29166,-10.58333 -13.22916,-13.93472 -7.9375,-3.52778 -18.16806,-3.52778 h -14.2875 v 96.66111 h 14.46389 q 15.69861,0 26.10555,-10.759722 10.58334,-10.936108 10.58334,-38.276388 z"
|
||||||
|
inkscape:connector-curvature="0" />
|
||||||
|
</g>
|
||||||
|
</g>
|
||||||
|
<g
|
||||||
|
inkscape:groupmode="layer"
|
||||||
|
id="layer5"
|
||||||
|
inkscape:label="path 1"
|
||||||
|
style="display:inline;opacity:0.24734982"
|
||||||
|
sodipodi:insensitive="true"
|
||||||
|
transform="translate(-4.3711946,-4.3733763)">
|
||||||
|
<path
|
||||||
|
inkscape:connector-curvature="0"
|
||||||
|
id="path4439"
|
||||||
|
d="m 135.46501,4.5782177 c -72.283329,0 -130.8889765,58.6051203 -130.8889765,130.8884523 0,72.28333 58.6056475,130.88899 130.8889765,130.88899 72.28333,0 130.88845,-58.60566 130.88845,-130.88899 0,-72.283332 -58.60512,-130.8884523 -130.88845,-130.8884523 z m 0,0.6938883 c 71.90852,0 130.19455,58.286041 130.19455,130.194564 0,71.90852 -58.28603,130.19456 -130.19455,130.19456 C 63.55649,265.66123 5.2699219,207.37519 5.2699216,135.46667 5.2699216,63.558147 63.55649,5.272106 135.46501,5.272106 Z"
|
||||||
|
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:176.3888855px;line-height:125%;font-family:'Fira Code';-inkscape-font-specification:'Fira Code';letter-spacing:-26.45833206px;word-spacing:0px;display:inline;opacity:0.75199998;fill:url(#linearGradient4380-5);fill-opacity:1;stroke:none;stroke-width:0.26631993px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
|
||||||
|
sodipodi:nodetypes="ssssssssss" />
|
||||||
|
</g>
|
||||||
|
<g
|
||||||
|
style="display:inline;opacity:0.36749118"
|
||||||
|
inkscape:label="path 2"
|
||||||
|
id="g4512"
|
||||||
|
inkscape:groupmode="layer"
|
||||||
|
sodipodi:insensitive="true"
|
||||||
|
transform="translate(-4.3711946,-4.3733763)">
|
||||||
|
<g
|
||||||
|
transform="matrix(1.0065636,0,0,1.0065636,-0.88913164,-0.88914604)"
|
||||||
|
style="fill:url(#linearGradient4530);fill-opacity:1"
|
||||||
|
id="g4514">
|
||||||
|
<g
|
||||||
|
transform="rotate(90)"
|
||||||
|
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:10.58333302px;line-height:125%;font-family:'Fira Code';-inkscape-font-specification:'Fira Code';letter-spacing:0px;word-spacing:0px;fill:url(#linearGradient4528);fill-opacity:1;stroke:none;stroke-width:0.26458332px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
|
||||||
|
aria-label=":D"
|
||||||
|
id="g4516">
|
||||||
|
<path
|
||||||
|
sodipodi:nodetypes="ssssssssss"
|
||||||
|
inkscape:connector-curvature="0"
|
||||||
|
id="path4518"
|
||||||
|
transform="matrix(0,-0.26458333,0.26458333,0,0,0.001665)"
|
||||||
|
d="M 512,55.460938 C 259.91593,55.460938 55.458984,259.9159 55.458984,512 55.458984,764.08406 259.91593,968.54102 512,968.54102 764.0841,968.54102 968.53906,764.08406 968.53906,512 968.53906,259.9159 764.0841,55.460938 512,55.460938 Z m 0,9.367187 C 759.02055,64.828125 959.17188,264.97946 959.17188,512 959.17188,759.02051 759.02055,959.17383 512,959.17383 264.97949,959.17383 64.826172,759.02051 64.826172,512 64.826172,264.97946 264.97949,64.828125 512,64.828125 Z"
|
||||||
|
style="font-size:176.3888855px;letter-spacing:-26.45833206px;fill:url(#linearGradient4526);fill-opacity:1;stroke-width:0.99999994px" />
|
||||||
|
</g>
|
||||||
|
</g>
|
||||||
|
<g
|
||||||
|
transform="rotate(90,-110.10081,-119.91599)"
|
||||||
|
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:10.58333302px;line-height:125%;font-family:'Fira Code';-inkscape-font-specification:'Fira Code';letter-spacing:0px;word-spacing:0px;display:none;fill:url(#linearGradient4536);fill-opacity:1;stroke:none;stroke-width:0.26458332px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
|
||||||
|
aria-label=":D"
|
||||||
|
id="g4520">
|
||||||
|
<path
|
||||||
|
inkscape:connector-curvature="0"
|
||||||
|
d="m 66.356665,-164.83375 q 0,-5.82083 4.056944,-9.87778 4.056945,-4.23333 10.054167,-4.23333 6.173611,0 10.230555,4.23333 4.056944,4.05695 4.056944,9.87778 0,5.99722 -4.056944,10.23056 -4.056944,4.23333 -10.230555,4.23333 -5.997222,0 -10.054167,-4.23333 -4.056944,-4.23334 -4.056944,-10.23056 z m 0,63.67639 q 0,-5.82083 4.056944,-10.05417 4.056945,-4.23333 10.054167,-4.23333 6.173611,0 10.230555,4.23333 4.056944,4.05695 4.056944,10.05417 0,6.17361 -4.056944,10.230555 -4.056944,4.056944 -10.230555,4.056944 -5.997222,0 -10.054167,-4.056944 -4.056944,-4.056945 -4.056944,-10.230555 z"
|
||||||
|
style="font-size:176.3888855px;letter-spacing:-26.45833206px;fill:url(#linearGradient4532);fill-opacity:1;stroke-width:0.26458332px"
|
||||||
|
id="path4522" />
|
||||||
|
<path
|
||||||
|
inkscape:connector-curvature="0"
|
||||||
|
d="m 204.57664,-136.08236 q 0,34.57222 -15.875,47.977777 -15.875,13.405555 -39.15833,13.405555 H 121.67387 V -196.23097 h 25.92916 q 25.57639,0 41.275,12.87639 15.69861,12.87639 15.69861,47.27222 z m -16.40416,0 q 0,-19.75556 -5.46806,-30.1625 -5.29166,-10.58333 -13.22916,-13.93472 -7.9375,-3.52778 -18.16806,-3.52778 h -14.2875 v 96.66111 h 14.46389 q 15.69861,0 26.10555,-10.759722 10.58334,-10.936108 10.58334,-38.276388 z"
|
||||||
|
style="font-size:176.3888855px;letter-spacing:-26.45833206px;fill:url(#linearGradient4534);fill-opacity:1;stroke-width:0.26458332px"
|
||||||
|
id="path4524" />
|
||||||
|
</g>
|
||||||
|
</g>
|
||||||
|
<g
|
||||||
|
style="display:inline;opacity:0.6501767"
|
||||||
|
inkscape:label="path 3"
|
||||||
|
id="g4538"
|
||||||
|
inkscape:groupmode="layer"
|
||||||
|
sodipodi:insensitive="true"
|
||||||
|
transform="translate(-4.3711946,-4.3733763)">
|
||||||
|
<g
|
||||||
|
transform="matrix(1.0065636,0,0,1.0065636,-0.88913164,-0.88914604)"
|
||||||
|
style="fill:url(#linearGradient4556);fill-opacity:1"
|
||||||
|
id="g4540">
|
||||||
|
<g
|
||||||
|
transform="rotate(90)"
|
||||||
|
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:10.58333302px;line-height:125%;font-family:'Fira Code';-inkscape-font-specification:'Fira Code';letter-spacing:0px;word-spacing:0px;fill:url(#linearGradient4554);fill-opacity:1;stroke:none;stroke-width:0.26458332px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
|
||||||
|
aria-label=":D"
|
||||||
|
id="g4542">
|
||||||
|
<path
|
||||||
|
sodipodi:nodetypes="ssssssssss"
|
||||||
|
inkscape:connector-curvature="0"
|
||||||
|
id="path4544"
|
||||||
|
transform="matrix(0,-0.26458333,0.26458333,0,0,0.001665)"
|
||||||
|
d="M 512,96.5625 C 282.67144,96.5625 96.568359,282.67142 96.568359,512 96.568359,741.32854 282.67144,927.43164 512,927.43164 741.32858,927.43164 927.4375,741.32854 927.4375,512 927.4375,282.67142 741.32858,96.5625 512,96.5625 Z m 0,18.47656 C 731.34481,115.03906 908.96094,292.6552 908.96094,512 908.96094,731.34477 731.34481,908.96094 512,908.96094 292.65523,908.96094 115.03906,731.34477 115.03906,512 115.03906,292.6552 292.65523,115.03906 512,115.03906 Z"
|
||||||
|
style="font-size:176.3888855px;letter-spacing:-26.45833206px;fill:url(#linearGradient4552);fill-opacity:1;stroke-width:0.99999994px" />
|
||||||
|
</g>
|
||||||
|
</g>
|
||||||
|
<g
|
||||||
|
transform="rotate(90,-110.10081,-119.91599)"
|
||||||
|
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:10.58333302px;line-height:125%;font-family:'Fira Code';-inkscape-font-specification:'Fira Code';letter-spacing:0px;word-spacing:0px;display:none;fill:url(#linearGradient4562);fill-opacity:1;stroke:none;stroke-width:0.26458332px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
|
||||||
|
aria-label=":D"
|
||||||
|
id="g4546">
|
||||||
|
<path
|
||||||
|
inkscape:connector-curvature="0"
|
||||||
|
d="m 66.356665,-164.83375 q 0,-5.82083 4.056944,-9.87778 4.056945,-4.23333 10.054167,-4.23333 6.173611,0 10.230555,4.23333 4.056944,4.05695 4.056944,9.87778 0,5.99722 -4.056944,10.23056 -4.056944,4.23333 -10.230555,4.23333 -5.997222,0 -10.054167,-4.23333 -4.056944,-4.23334 -4.056944,-10.23056 z m 0,63.67639 q 0,-5.82083 4.056944,-10.05417 4.056945,-4.23333 10.054167,-4.23333 6.173611,0 10.230555,4.23333 4.056944,4.05695 4.056944,10.05417 0,6.17361 -4.056944,10.230555 -4.056944,4.056944 -10.230555,4.056944 -5.997222,0 -10.054167,-4.056944 -4.056944,-4.056945 -4.056944,-10.230555 z"
|
||||||
|
style="font-size:176.3888855px;letter-spacing:-26.45833206px;fill:url(#linearGradient4558);fill-opacity:1;stroke-width:0.26458332px"
|
||||||
|
id="path4548" />
|
||||||
|
<path
|
||||||
|
inkscape:connector-curvature="0"
|
||||||
|
d="m 204.57664,-136.08236 q 0,34.57222 -15.875,47.977777 -15.875,13.405555 -39.15833,13.405555 H 121.67387 V -196.23097 h 25.92916 q 25.57639,0 41.275,12.87639 15.69861,12.87639 15.69861,47.27222 z m -16.40416,0 q 0,-19.75556 -5.46806,-30.1625 -5.29166,-10.58333 -13.22916,-13.93472 -7.9375,-3.52778 -18.16806,-3.52778 h -14.2875 v 96.66111 h 14.46389 q 15.69861,0 26.10555,-10.759722 10.58334,-10.936108 10.58334,-38.276388 z"
|
||||||
|
style="font-size:176.3888855px;letter-spacing:-26.45833206px;fill:url(#linearGradient4560);fill-opacity:1;stroke-width:0.26458332px"
|
||||||
|
id="path4550" />
|
||||||
|
</g>
|
||||||
|
</g>
|
||||||
|
<g
|
||||||
|
inkscape:groupmode="layer"
|
||||||
|
id="layer3"
|
||||||
|
inkscape:label="light"
|
||||||
|
style="display:inline;opacity:1"
|
||||||
|
transform="translate(-4.3711946,-4.3733763)">
|
||||||
|
<g
|
||||||
|
id="g4360-5"
|
||||||
|
style="display:inline;fill:url(#linearGradient4332);fill-opacity:1"
|
||||||
|
transform="matrix(1.002648,0,0,1.002648,-1.0727108,-1.0727166)">
|
||||||
|
<g
|
||||||
|
id="text4141-2-9"
|
||||||
|
aria-label=":D"
|
||||||
|
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:10.58333302px;line-height:125%;font-family:'Fira Code';-inkscape-font-specification:'Fira Code';letter-spacing:0px;word-spacing:0px;fill:url(#linearGradient4187);fill-opacity:1;stroke:none;stroke-width:0.26458332px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
|
||||||
|
transform="rotate(90)">
|
||||||
|
<path
|
||||||
|
inkscape:connector-curvature="0"
|
||||||
|
style="font-size:176.3888855px;letter-spacing:-26.45833206px;fill:url(#linearGradient4184);fill-opacity:1;stroke-width:0.99999994px"
|
||||||
|
d="M 512,20.529297 C 240.58464,20.529297 20.527344,240.58461 20.527344,512 c 0,271.41536 220.057296,491.4727 491.472656,491.4727 271.4154,0 491.4707,-220.05734 491.4707,-491.4727 C 1003.4707,240.58461 783.4154,20.529297 512,20.529297 Z m 0,2.605469 c 270.00802,0 488.8652,218.857204 488.8652,488.865234 0,270.00802 -218.85718,488.8652 -488.8652,488.8652 C 241.992,1000.8652 23.132813,782.00802 23.132812,512 23.132812,241.99197 241.992,23.134766 512,23.134766 Z m 0,32.326172 C 259.91593,55.460938 55.458984,259.9159 55.458984,512 55.458984,764.08406 259.91593,968.54102 512,968.54102 764.0841,968.54102 968.53906,764.08406 968.53906,512 968.53906,259.9159 764.0841,55.460938 512,55.460938 Z m 0,9.367187 C 759.02055,64.828125 959.17188,264.97946 959.17188,512 959.17188,759.02051 759.02055,959.17383 512,959.17383 264.97949,959.17383 64.826172,759.02051 64.826172,512 64.826172,264.97946 264.97949,64.828125 512,64.828125 Z M 512,96.5625 C 282.67144,96.5625 96.568359,282.67142 96.568359,512 96.568359,741.32854 282.67144,927.43164 512,927.43164 741.32858,927.43164 927.4375,741.32854 927.4375,512 927.4375,282.67142 741.32858,96.5625 512,96.5625 Z m 0,18.47656 C 731.34481,115.03906 908.96094,292.6552 908.96094,512 908.96094,731.34477 731.34481,908.96094 512,908.96094 292.65523,908.96094 115.03906,731.34477 115.03906,512 115.03906,292.6552 292.65523,115.03906 512,115.03906 Z m 0,32.90235 C 311.12038,147.94141 147.93945,311.12036 147.93945,512 147.93945,712.87962 311.12038,876.06055 512,876.06055 712.87966,876.06055 876.05859,712.87962 876.05859,512 876.05859,311.12036 712.87966,147.94141 512,147.94141 Z m 0,31.16601 c 184.03556,0 332.89258,148.85702 332.89258,332.89258 0,184.03552 -148.85702,332.89453 -332.89258,332.89453 -184.03553,0 -332.89453,-148.85901 -332.89453,-332.89453 0,-184.03556 148.859,-332.89258 332.89453,-332.89258 z m -129.66602,71.68946 c -15.55555,0 -28.44574,5.11176 -38.66796,15.33398 -10.22223,10.22222 -15.33204,22.88889 -15.33204,38 0,15.55555 5.10981,28.44379 15.33204,38.66602 10.22222,10.22222 23.11241,15.33398 38.66796,15.33398 15.11111,0 27.77777,-5.11176 38,-15.33398 10.66666,-10.22223 16,-23.11047 16,-38.66602 0,-15.11111 -5.33334,-27.77778 -16,-38 -10.66668,-10.22222 -23.33334,-15.33398 -38,-15.33398 z m 240.66602,0 c -15.11111,0 -27.99933,5.11176 -38.66602,15.33398 -10.66665,10.22222 -16,22.88889 -16,38 0,15.55555 5.33335,28.44379 16,38.66602 10.66669,10.22222 23.55491,15.33398 38.66602,15.33398 14.66666,0 27.11175,-5.11176 37.33398,-15.33398 10.66666,-10.22223 16,-23.11047 16,-38.66602 0,-15.11111 -5.33334,-27.77778 -16,-38 C 650.11175,255.90864 637.66666,250.79688 623,250.79688 Z M 282.33398,459.86914 v 105.33398 c 0,58.66666 16.88824,108 50.66602,148 33.77778,40.00001 94.22288,60 181.33398,60 86.66666,0 146.22157,-19.77843 178.66602,-59.33398 32.44445,-39.55555 48.66602,-91.55555 48.66602,-156 v -98 z m 46.66602,58 h 365.33398 v 54 c 0,25.77779 -4.44509,48.66797 -13.33398,68.66797 -8.44445,20 -25.99936,36.66668 -52.66602,50 -26.22221,13.77779 -64.22221,20.66601 -114,20.66601 -68.88889,0 -117.11242,-13.33331 -144.66796,-40 C 342.5549,644.98091 329,612.09266 329,572.53711 Z"
|
||||||
|
transform="matrix(0,-0.26458333,0.26458333,0,0,0.001665)"
|
||||||
|
id="path4247-2" />
|
||||||
|
</g>
|
||||||
|
</g>
|
||||||
|
</g>
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 30 KiB |
79
Editor/resources/IconA.svg
Normal file
@@ -0,0 +1,79 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||||
|
<!-- Created with Inkscape (http://www.inkscape.org/) -->
|
||||||
|
|
||||||
|
<svg
|
||||||
|
xmlns:dc="http://purl.org/dc/elements/1.1/"
|
||||||
|
xmlns:cc="http://creativecommons.org/ns#"
|
||||||
|
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
|
||||||
|
xmlns:svg="http://www.w3.org/2000/svg"
|
||||||
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
|
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||||
|
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||||
|
width="20"
|
||||||
|
height="20"
|
||||||
|
viewBox="0 0 5.2916665 5.2916668"
|
||||||
|
version="1.1"
|
||||||
|
id="svg8"
|
||||||
|
inkscape:version="0.92.2 2405546, 2018-03-11"
|
||||||
|
sodipodi:docname="IconA.svg">
|
||||||
|
<defs
|
||||||
|
id="defs2" />
|
||||||
|
<sodipodi:namedview
|
||||||
|
id="base"
|
||||||
|
pagecolor="#353535"
|
||||||
|
bordercolor="#666666"
|
||||||
|
borderopacity="1.0"
|
||||||
|
inkscape:pageopacity="0"
|
||||||
|
inkscape:pageshadow="2"
|
||||||
|
inkscape:zoom="42.15"
|
||||||
|
inkscape:cx="10.765381"
|
||||||
|
inkscape:cy="12.799167"
|
||||||
|
inkscape:document-units="px"
|
||||||
|
inkscape:current-layer="layer1"
|
||||||
|
showgrid="true"
|
||||||
|
units="px"
|
||||||
|
inkscape:window-width="3840"
|
||||||
|
inkscape:window-height="2079"
|
||||||
|
inkscape:window-x="0"
|
||||||
|
inkscape:window-y="40"
|
||||||
|
inkscape:window-maximized="1"
|
||||||
|
gridtolerance="10"
|
||||||
|
showguides="false"
|
||||||
|
objecttolerance="17">
|
||||||
|
<inkscape:grid
|
||||||
|
type="xygrid"
|
||||||
|
id="grid817"
|
||||||
|
empspacing="0"
|
||||||
|
spacingx="0.52916666"
|
||||||
|
spacingy="0.52916666"
|
||||||
|
visible="true" />
|
||||||
|
</sodipodi:namedview>
|
||||||
|
<metadata
|
||||||
|
id="metadata5">
|
||||||
|
<rdf:RDF>
|
||||||
|
<cc:Work
|
||||||
|
rdf:about="">
|
||||||
|
<dc:format>image/svg+xml</dc:format>
|
||||||
|
<dc:type
|
||||||
|
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
|
||||||
|
<dc:title></dc:title>
|
||||||
|
</cc:Work>
|
||||||
|
</rdf:RDF>
|
||||||
|
</metadata>
|
||||||
|
<g
|
||||||
|
inkscape:label="Layer 1"
|
||||||
|
inkscape:groupmode="layer"
|
||||||
|
id="layer1"
|
||||||
|
transform="translate(0,-291.70832)">
|
||||||
|
<g
|
||||||
|
aria-label="A"
|
||||||
|
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:7.33670712px;line-height:1.25;font-family:'Noto Serif';-inkscape-font-specification:'Noto Serif';letter-spacing:0px;word-spacing:0px;fill:#ffffff;fill-opacity:1;stroke:none;stroke-width:1.37563241"
|
||||||
|
id="text1395">
|
||||||
|
<path
|
||||||
|
d="m 0.04443603,296.98746 0.05869366,-0.30814 h 0.13939743 q 0.13939744,0 0.24211134,-0.044 0.1027139,-0.044 0.19809109,-0.16875 0.1027139,-0.12472 0.24211133,-0.3595 l 2.55317412,-4.358 h 0.5722631 l 0.6969872,4.54142 q 0.036684,0.22744 0.124724,0.30814 0.095377,0.0807 0.3081417,0.0807 h 0.095377 l -0.058694,0.30814 H 3.2212302 l 0.058694,-0.30814 h 0.1687442 q 0.2347747,0 0.3815088,-0.0954 0.1467341,-0.10272 0.1467341,-0.2788 0,-0.0587 -0.00734,-0.12472 0,-0.0734 -0.00734,-0.12472 l -0.117381,-0.82171 H 1.9226331 l -0.4475392,0.77036 q -0.1393974,0.25678 -0.1393974,0.41085 0,0.26413 0.4108556,0.26413 h 0.1687442 l -0.058694,0.30814 z m 2.87598917,-3.47027 -0.7850276,1.34996 h 1.6580958 l -0.1834177,-1.28392 q -0.04402,-0.32282 -0.080704,-0.60895 -0.029347,-0.28613 -0.036684,-0.55025 -0.1173873,0.26412 -0.2494481,0.50623 -0.124724,0.24211 -0.3228144,0.58693 z"
|
||||||
|
style="font-style:italic;font-variant:normal;font-weight:normal;font-stretch:normal;font-family:'Noto Serif';-inkscape-font-specification:'Noto Serif Italic';fill:#ffffff;fill-opacity:1;stroke-width:1.37563241"
|
||||||
|
id="path1397"
|
||||||
|
inkscape:connector-curvature="0" />
|
||||||
|
</g>
|
||||||
|
</g>
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 3.4 KiB |
81
Editor/resources/IconADSR.svg
Normal file
@@ -0,0 +1,81 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||||
|
<!-- Created with Inkscape (http://www.inkscape.org/) -->
|
||||||
|
|
||||||
|
<svg
|
||||||
|
xmlns:dc="http://purl.org/dc/elements/1.1/"
|
||||||
|
xmlns:cc="http://creativecommons.org/ns#"
|
||||||
|
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
|
||||||
|
xmlns:svg="http://www.w3.org/2000/svg"
|
||||||
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
|
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||||
|
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||||
|
width="16"
|
||||||
|
height="16"
|
||||||
|
viewBox="0 0 4.2333332 4.2333335"
|
||||||
|
id="svg2"
|
||||||
|
version="1.1"
|
||||||
|
inkscape:version="0.92.2 2405546, 2018-03-11"
|
||||||
|
sodipodi:docname="IconADSR.svg">
|
||||||
|
<sodipodi:namedview
|
||||||
|
id="base"
|
||||||
|
pagecolor="#393939"
|
||||||
|
bordercolor="#666666"
|
||||||
|
borderopacity="1.0"
|
||||||
|
inkscape:pageopacity="0"
|
||||||
|
inkscape:pageshadow="2"
|
||||||
|
inkscape:zoom="30.086227"
|
||||||
|
inkscape:cx="7.2902772"
|
||||||
|
inkscape:cy="8.0995259"
|
||||||
|
inkscape:document-units="px"
|
||||||
|
inkscape:current-layer="layer1"
|
||||||
|
showgrid="true"
|
||||||
|
units="px"
|
||||||
|
inkscape:window-width="1260"
|
||||||
|
inkscape:window-height="787"
|
||||||
|
inkscape:window-x="267"
|
||||||
|
inkscape:window-y="1022"
|
||||||
|
inkscape:window-maximized="0"
|
||||||
|
showborder="false"
|
||||||
|
objecttolerance="4"
|
||||||
|
gridtolerance="4"
|
||||||
|
guidetolerance="5">
|
||||||
|
<inkscape:grid
|
||||||
|
visible="true"
|
||||||
|
empspacing="1"
|
||||||
|
id="grid4173"
|
||||||
|
type="xygrid" />
|
||||||
|
</sodipodi:namedview>
|
||||||
|
<defs
|
||||||
|
id="defs4" />
|
||||||
|
<metadata
|
||||||
|
id="metadata7">
|
||||||
|
<rdf:RDF>
|
||||||
|
<cc:Work
|
||||||
|
rdf:about="">
|
||||||
|
<dc:format>image/svg+xml</dc:format>
|
||||||
|
<dc:type
|
||||||
|
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
|
||||||
|
<dc:title></dc:title>
|
||||||
|
</cc:Work>
|
||||||
|
</rdf:RDF>
|
||||||
|
</metadata>
|
||||||
|
<g
|
||||||
|
transform="translate(0,-292.76665)"
|
||||||
|
id="layer1"
|
||||||
|
inkscape:groupmode="layer"
|
||||||
|
inkscape:label="Layer 1">
|
||||||
|
<rect
|
||||||
|
style="fill:#ff6600;fill-opacity:1;stroke:none;stroke-width:0.39687499;stroke-linecap:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;paint-order:normal"
|
||||||
|
id="rect1235"
|
||||||
|
width="3.7041667"
|
||||||
|
height="3.7041805"
|
||||||
|
x="0.26458335"
|
||||||
|
y="293.03122" />
|
||||||
|
<path
|
||||||
|
style="fill:none;stroke:#000000;stroke-width:0.5291667;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
|
||||||
|
d="M 0.26458333,296.7354 1.0583334,293.47246 1.5875,294.35415 H 2.9104167 L 3.96875,296.7354"
|
||||||
|
id="path1834"
|
||||||
|
inkscape:connector-curvature="0"
|
||||||
|
sodipodi:nodetypes="ccccc" />
|
||||||
|
</g>
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 2.5 KiB |
75
Editor/resources/IconAdd.svg
Normal file
@@ -0,0 +1,75 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||||
|
<!-- Created with Inkscape (http://www.inkscape.org/) -->
|
||||||
|
|
||||||
|
<svg
|
||||||
|
xmlns:dc="http://purl.org/dc/elements/1.1/"
|
||||||
|
xmlns:cc="http://creativecommons.org/ns#"
|
||||||
|
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
|
||||||
|
xmlns:svg="http://www.w3.org/2000/svg"
|
||||||
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
|
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||||
|
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||||
|
width="24"
|
||||||
|
height="24"
|
||||||
|
viewBox="0 0 6.3499998 6.3500004"
|
||||||
|
version="1.1"
|
||||||
|
id="svg8"
|
||||||
|
inkscape:version="0.92.2 2405546, 2018-03-11"
|
||||||
|
sodipodi:docname="IconAdd.svg">
|
||||||
|
<defs
|
||||||
|
id="defs2" />
|
||||||
|
<sodipodi:namedview
|
||||||
|
id="base"
|
||||||
|
pagecolor="#353535"
|
||||||
|
bordercolor="#666666"
|
||||||
|
borderopacity="1.0"
|
||||||
|
inkscape:pageopacity="0"
|
||||||
|
inkscape:pageshadow="2"
|
||||||
|
inkscape:zoom="111.23937"
|
||||||
|
inkscape:cx="14.81887"
|
||||||
|
inkscape:cy="16.006269"
|
||||||
|
inkscape:document-units="px"
|
||||||
|
inkscape:current-layer="layer1"
|
||||||
|
showgrid="true"
|
||||||
|
units="px"
|
||||||
|
inkscape:window-width="3840"
|
||||||
|
inkscape:window-height="2079"
|
||||||
|
inkscape:window-x="0"
|
||||||
|
inkscape:window-y="40"
|
||||||
|
inkscape:window-maximized="1"
|
||||||
|
gridtolerance="4"
|
||||||
|
showguides="false"
|
||||||
|
showborder="true"
|
||||||
|
objecttolerance="13">
|
||||||
|
<inkscape:grid
|
||||||
|
type="xygrid"
|
||||||
|
id="grid817"
|
||||||
|
empspacing="0"
|
||||||
|
spacingx="0.52916666"
|
||||||
|
spacingy="0.52916666"
|
||||||
|
visible="true" />
|
||||||
|
</sodipodi:namedview>
|
||||||
|
<metadata
|
||||||
|
id="metadata5">
|
||||||
|
<rdf:RDF>
|
||||||
|
<cc:Work
|
||||||
|
rdf:about="">
|
||||||
|
<dc:format>image/svg+xml</dc:format>
|
||||||
|
<dc:type
|
||||||
|
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
|
||||||
|
<dc:title></dc:title>
|
||||||
|
</cc:Work>
|
||||||
|
</rdf:RDF>
|
||||||
|
</metadata>
|
||||||
|
<g
|
||||||
|
inkscape:label="Layer 1"
|
||||||
|
inkscape:groupmode="layer"
|
||||||
|
id="layer1"
|
||||||
|
transform="translate(0,-290.64999)">
|
||||||
|
<path
|
||||||
|
style="fill:#66ff00;stroke:none;stroke-width:0.26458335px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
|
||||||
|
d="m 0,292.76666 h 2.1166667 v -2.11667 h 2.1166667 v 2.11667 h 2.1166665 v 2.11666 H 4.2333334 v 2.11667 H 2.1166667 v -2.11667 H 0 Z"
|
||||||
|
id="path846"
|
||||||
|
inkscape:connector-curvature="0" />
|
||||||
|
</g>
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 2.2 KiB |
79
Editor/resources/IconB.svg
Normal file
@@ -0,0 +1,79 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||||
|
<!-- Created with Inkscape (http://www.inkscape.org/) -->
|
||||||
|
|
||||||
|
<svg
|
||||||
|
xmlns:dc="http://purl.org/dc/elements/1.1/"
|
||||||
|
xmlns:cc="http://creativecommons.org/ns#"
|
||||||
|
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
|
||||||
|
xmlns:svg="http://www.w3.org/2000/svg"
|
||||||
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
|
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||||
|
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||||
|
width="20"
|
||||||
|
height="20"
|
||||||
|
viewBox="0 0 5.2916665 5.2916668"
|
||||||
|
version="1.1"
|
||||||
|
id="svg8"
|
||||||
|
inkscape:version="0.92.2 2405546, 2018-03-11"
|
||||||
|
sodipodi:docname="IconB.svg">
|
||||||
|
<defs
|
||||||
|
id="defs2" />
|
||||||
|
<sodipodi:namedview
|
||||||
|
id="base"
|
||||||
|
pagecolor="#353535"
|
||||||
|
bordercolor="#666666"
|
||||||
|
borderopacity="1.0"
|
||||||
|
inkscape:pageopacity="0"
|
||||||
|
inkscape:pageshadow="2"
|
||||||
|
inkscape:zoom="42.15"
|
||||||
|
inkscape:cx="10.765381"
|
||||||
|
inkscape:cy="12.799167"
|
||||||
|
inkscape:document-units="px"
|
||||||
|
inkscape:current-layer="layer1"
|
||||||
|
showgrid="true"
|
||||||
|
units="px"
|
||||||
|
inkscape:window-width="3840"
|
||||||
|
inkscape:window-height="2079"
|
||||||
|
inkscape:window-x="0"
|
||||||
|
inkscape:window-y="40"
|
||||||
|
inkscape:window-maximized="1"
|
||||||
|
gridtolerance="10"
|
||||||
|
showguides="false"
|
||||||
|
objecttolerance="17">
|
||||||
|
<inkscape:grid
|
||||||
|
type="xygrid"
|
||||||
|
id="grid817"
|
||||||
|
empspacing="0"
|
||||||
|
spacingx="0.52916666"
|
||||||
|
spacingy="0.52916666"
|
||||||
|
visible="true" />
|
||||||
|
</sodipodi:namedview>
|
||||||
|
<metadata
|
||||||
|
id="metadata5">
|
||||||
|
<rdf:RDF>
|
||||||
|
<cc:Work
|
||||||
|
rdf:about="">
|
||||||
|
<dc:format>image/svg+xml</dc:format>
|
||||||
|
<dc:type
|
||||||
|
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
|
||||||
|
<dc:title></dc:title>
|
||||||
|
</cc:Work>
|
||||||
|
</rdf:RDF>
|
||||||
|
</metadata>
|
||||||
|
<g
|
||||||
|
inkscape:label="Layer 1"
|
||||||
|
inkscape:groupmode="layer"
|
||||||
|
id="layer1"
|
||||||
|
transform="translate(0,-291.70832)">
|
||||||
|
<g
|
||||||
|
aria-label="B"
|
||||||
|
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:7.34962893px;line-height:1.25;font-family:'Noto Serif';-inkscape-font-specification:'Noto Serif';letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1.37805545"
|
||||||
|
id="text1421">
|
||||||
|
<path
|
||||||
|
d="m 0.31920594,296.97952 0.058797,-0.30868 h 0.0955452 q 0.24988739,0 0.44832737,-0.0882 0.19843999,-0.0955 0.27193629,-0.44097 l 0.7643614,-3.60132 q 0.029398,-0.1176 0.029398,-0.20579 0,-0.19109 -0.1616918,-0.24254 -0.1543422,-0.0514 -0.3674815,-0.0514 h -0.095545 l 0.066147,-0.30868 h 1.9035539 q 0.8452073,0 1.2788354,0.27928 0.4409778,0.27929 0.4409778,0.82316 0,0.40423 -0.1616919,0.68352 -0.1543422,0.27193 -0.4262784,0.44098 -0.2719363,0.16904 -0.6100193,0.24253 l -0.00735,0.0294 q 0.39688,0.0735 0.6467674,0.34543 0.2498873,0.26459 0.2498873,0.72762 0,0.80846 -0.5365229,1.24208 -0.5365229,0.43363 -1.5801702,0.43363 z m 2.05789606,-2.9325 h 0.5659215 q 0.6908651,0 0.9995495,-0.28663 0.3086844,-0.29399 0.3086844,-0.83051 0,-0.83051 -1.0142488,-0.83051 H 2.7960309 Z m -0.5438725,2.56502 h 0.712914 q 0.7570118,0 1.0803955,-0.34543 0.3233836,-0.35278 0.3233836,-1.01425 0,-0.83786 -1.028948,-0.83786 H 2.3036057 Z"
|
||||||
|
style="font-style:italic;font-variant:normal;font-weight:normal;font-stretch:normal;font-family:'Noto Serif';-inkscape-font-specification:'Noto Serif Italic';fill:#ffffff;fill-opacity:1;stroke-width:1.37805545"
|
||||||
|
id="path1423"
|
||||||
|
inkscape:connector-curvature="0" />
|
||||||
|
</g>
|
||||||
|
</g>
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 3.4 KiB |
74
Editor/resources/IconBack.svg
Normal file
@@ -0,0 +1,74 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||||
|
<!-- Created with Inkscape (http://www.inkscape.org/) -->
|
||||||
|
|
||||||
|
<svg
|
||||||
|
xmlns:dc="http://purl.org/dc/elements/1.1/"
|
||||||
|
xmlns:cc="http://creativecommons.org/ns#"
|
||||||
|
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
|
||||||
|
xmlns:svg="http://www.w3.org/2000/svg"
|
||||||
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
|
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||||
|
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||||
|
width="20"
|
||||||
|
height="20"
|
||||||
|
viewBox="0 0 5.2916665 5.2916669"
|
||||||
|
id="svg2"
|
||||||
|
version="1.1"
|
||||||
|
inkscape:version="0.92.2 2405546, 2018-03-11"
|
||||||
|
sodipodi:docname="IconBack.svg">
|
||||||
|
<defs
|
||||||
|
id="defs4" />
|
||||||
|
<sodipodi:namedview
|
||||||
|
id="base"
|
||||||
|
pagecolor="#393939"
|
||||||
|
bordercolor="#666666"
|
||||||
|
borderopacity="1.0"
|
||||||
|
inkscape:pageopacity="0"
|
||||||
|
inkscape:pageshadow="2"
|
||||||
|
inkscape:zoom="39.383707"
|
||||||
|
inkscape:cx="6.3383887"
|
||||||
|
inkscape:cy="7.7203454"
|
||||||
|
inkscape:document-units="px"
|
||||||
|
inkscape:current-layer="layer1"
|
||||||
|
showgrid="true"
|
||||||
|
units="px"
|
||||||
|
inkscape:window-width="3840"
|
||||||
|
inkscape:window-height="2079"
|
||||||
|
inkscape:window-x="0"
|
||||||
|
inkscape:window-y="40"
|
||||||
|
inkscape:window-maximized="1"
|
||||||
|
showborder="true"
|
||||||
|
objecttolerance="4"
|
||||||
|
gridtolerance="4"
|
||||||
|
guidetolerance="5">
|
||||||
|
<inkscape:grid
|
||||||
|
type="xygrid"
|
||||||
|
id="grid4173"
|
||||||
|
empspacing="1"
|
||||||
|
visible="true" />
|
||||||
|
</sodipodi:namedview>
|
||||||
|
<metadata
|
||||||
|
id="metadata7">
|
||||||
|
<rdf:RDF>
|
||||||
|
<cc:Work
|
||||||
|
rdf:about="">
|
||||||
|
<dc:format>image/svg+xml</dc:format>
|
||||||
|
<dc:type
|
||||||
|
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
|
||||||
|
<dc:title></dc:title>
|
||||||
|
</cc:Work>
|
||||||
|
</rdf:RDF>
|
||||||
|
</metadata>
|
||||||
|
<g
|
||||||
|
inkscape:label="Layer 1"
|
||||||
|
inkscape:groupmode="layer"
|
||||||
|
id="layer1"
|
||||||
|
transform="translate(0,-291.70832)">
|
||||||
|
<path
|
||||||
|
style="fill:#ffffff;fill-opacity:1;stroke:none;stroke-width:0.26458332px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
|
||||||
|
d="m 0,294.35415 2.6458333,-2.64583 v 1.5875 h 2.6458334 v 1.85208 H 2.6458333 l 0,1.85209 z"
|
||||||
|
id="path841"
|
||||||
|
inkscape:connector-curvature="0"
|
||||||
|
sodipodi:nodetypes="cccccccc" />
|
||||||
|
</g>
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 2.2 KiB |
74
Editor/resources/IconBackDisabled.svg
Normal file
@@ -0,0 +1,74 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||||
|
<!-- Created with Inkscape (http://www.inkscape.org/) -->
|
||||||
|
|
||||||
|
<svg
|
||||||
|
xmlns:dc="http://purl.org/dc/elements/1.1/"
|
||||||
|
xmlns:cc="http://creativecommons.org/ns#"
|
||||||
|
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
|
||||||
|
xmlns:svg="http://www.w3.org/2000/svg"
|
||||||
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
|
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||||
|
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||||
|
width="20"
|
||||||
|
height="20"
|
||||||
|
viewBox="0 0 5.2916665 5.2916669"
|
||||||
|
id="svg2"
|
||||||
|
version="1.1"
|
||||||
|
inkscape:version="0.92.2 2405546, 2018-03-11"
|
||||||
|
sodipodi:docname="IconBackDisabled.svg">
|
||||||
|
<defs
|
||||||
|
id="defs4" />
|
||||||
|
<sodipodi:namedview
|
||||||
|
id="base"
|
||||||
|
pagecolor="#393939"
|
||||||
|
bordercolor="#666666"
|
||||||
|
borderopacity="1.0"
|
||||||
|
inkscape:pageopacity="0"
|
||||||
|
inkscape:pageshadow="2"
|
||||||
|
inkscape:zoom="39.383707"
|
||||||
|
inkscape:cx="1.7552752"
|
||||||
|
inkscape:cy="7.7203454"
|
||||||
|
inkscape:document-units="px"
|
||||||
|
inkscape:current-layer="layer1"
|
||||||
|
showgrid="true"
|
||||||
|
units="px"
|
||||||
|
inkscape:window-width="3840"
|
||||||
|
inkscape:window-height="2079"
|
||||||
|
inkscape:window-x="0"
|
||||||
|
inkscape:window-y="40"
|
||||||
|
inkscape:window-maximized="1"
|
||||||
|
showborder="true"
|
||||||
|
objecttolerance="4"
|
||||||
|
gridtolerance="4"
|
||||||
|
guidetolerance="5">
|
||||||
|
<inkscape:grid
|
||||||
|
type="xygrid"
|
||||||
|
id="grid4173"
|
||||||
|
empspacing="1"
|
||||||
|
visible="true" />
|
||||||
|
</sodipodi:namedview>
|
||||||
|
<metadata
|
||||||
|
id="metadata7">
|
||||||
|
<rdf:RDF>
|
||||||
|
<cc:Work
|
||||||
|
rdf:about="">
|
||||||
|
<dc:format>image/svg+xml</dc:format>
|
||||||
|
<dc:type
|
||||||
|
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
|
||||||
|
<dc:title></dc:title>
|
||||||
|
</cc:Work>
|
||||||
|
</rdf:RDF>
|
||||||
|
</metadata>
|
||||||
|
<g
|
||||||
|
inkscape:label="Layer 1"
|
||||||
|
inkscape:groupmode="layer"
|
||||||
|
id="layer1"
|
||||||
|
transform="translate(0,-291.70832)">
|
||||||
|
<path
|
||||||
|
style="fill:#ffffff;fill-opacity:0.39215687;stroke:none;stroke-width:0.26458332px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
|
||||||
|
d="m 0,294.35415 2.6458333,-2.64583 v 1.5875 h 2.6458334 v 1.85208 H 2.6458333 v 1.85209 z"
|
||||||
|
id="path841"
|
||||||
|
inkscape:connector-curvature="0"
|
||||||
|
sodipodi:nodetypes="cccccccc" />
|
||||||
|
</g>
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 2.2 KiB |
87
Editor/resources/IconCurve.svg
Normal file
@@ -0,0 +1,87 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||||
|
<!-- Created with Inkscape (http://www.inkscape.org/) -->
|
||||||
|
|
||||||
|
<svg
|
||||||
|
xmlns:dc="http://purl.org/dc/elements/1.1/"
|
||||||
|
xmlns:cc="http://creativecommons.org/ns#"
|
||||||
|
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
|
||||||
|
xmlns:svg="http://www.w3.org/2000/svg"
|
||||||
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
|
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||||
|
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||||
|
width="16"
|
||||||
|
height="16"
|
||||||
|
viewBox="0 0 4.2333332 4.2333335"
|
||||||
|
id="svg2"
|
||||||
|
version="1.1"
|
||||||
|
inkscape:version="0.92.2 2405546, 2018-03-11"
|
||||||
|
sodipodi:docname="IconCurve.svg">
|
||||||
|
<sodipodi:namedview
|
||||||
|
id="base"
|
||||||
|
pagecolor="#393939"
|
||||||
|
bordercolor="#666666"
|
||||||
|
borderopacity="1.0"
|
||||||
|
inkscape:pageopacity="0"
|
||||||
|
inkscape:pageshadow="2"
|
||||||
|
inkscape:zoom="30.086227"
|
||||||
|
inkscape:cx="-2.7199818"
|
||||||
|
inkscape:cy="9.4290379"
|
||||||
|
inkscape:document-units="px"
|
||||||
|
inkscape:current-layer="layer1"
|
||||||
|
showgrid="true"
|
||||||
|
units="px"
|
||||||
|
inkscape:window-width="1260"
|
||||||
|
inkscape:window-height="787"
|
||||||
|
inkscape:window-x="267"
|
||||||
|
inkscape:window-y="1022"
|
||||||
|
inkscape:window-maximized="0"
|
||||||
|
showborder="false"
|
||||||
|
objecttolerance="4"
|
||||||
|
gridtolerance="4"
|
||||||
|
guidetolerance="5">
|
||||||
|
<inkscape:grid
|
||||||
|
visible="true"
|
||||||
|
empspacing="1"
|
||||||
|
id="grid4173"
|
||||||
|
type="xygrid" />
|
||||||
|
</sodipodi:namedview>
|
||||||
|
<defs
|
||||||
|
id="defs4" />
|
||||||
|
<metadata
|
||||||
|
id="metadata7">
|
||||||
|
<rdf:RDF>
|
||||||
|
<cc:Work
|
||||||
|
rdf:about="">
|
||||||
|
<dc:format>image/svg+xml</dc:format>
|
||||||
|
<dc:type
|
||||||
|
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
|
||||||
|
<dc:title />
|
||||||
|
</cc:Work>
|
||||||
|
</rdf:RDF>
|
||||||
|
</metadata>
|
||||||
|
<g
|
||||||
|
transform="translate(0,-292.76665)"
|
||||||
|
id="layer1"
|
||||||
|
inkscape:groupmode="layer"
|
||||||
|
inkscape:label="Layer 1">
|
||||||
|
<rect
|
||||||
|
style="fill:#00ffcc;fill-opacity:1;stroke:none;stroke-width:0.39687499;stroke-linecap:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;paint-order:normal"
|
||||||
|
id="rect1235"
|
||||||
|
width="3.7041667"
|
||||||
|
height="3.7041805"
|
||||||
|
x="0.26458335"
|
||||||
|
y="293.03122" />
|
||||||
|
<path
|
||||||
|
style="fill:none;stroke:#808080;stroke-width:0.52916667;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:0.52916667, 0.52916666999999995;stroke-opacity:1;stroke-dashoffset:0"
|
||||||
|
d="m 0.26458333,292.76665 0,3.96875 H 4.2333333"
|
||||||
|
id="path1231"
|
||||||
|
inkscape:connector-curvature="0"
|
||||||
|
sodipodi:nodetypes="ccc" />
|
||||||
|
<path
|
||||||
|
style="fill:none;stroke:#000000;stroke-width:0.5291667;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
|
||||||
|
d="m 0,296.7354 c 2.0787582,0 3.96875,-2.11667 3.96875,-3.96875"
|
||||||
|
id="path1233"
|
||||||
|
inkscape:connector-curvature="0"
|
||||||
|
sodipodi:nodetypes="cc" />
|
||||||
|
</g>
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 2.8 KiB |
84
Editor/resources/IconFX.svg
Normal file
@@ -0,0 +1,84 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||||
|
<!-- Created with Inkscape (http://www.inkscape.org/) -->
|
||||||
|
|
||||||
|
<svg
|
||||||
|
xmlns:dc="http://purl.org/dc/elements/1.1/"
|
||||||
|
xmlns:cc="http://creativecommons.org/ns#"
|
||||||
|
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
|
||||||
|
xmlns:svg="http://www.w3.org/2000/svg"
|
||||||
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
|
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||||
|
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||||
|
width="20"
|
||||||
|
height="20"
|
||||||
|
viewBox="0 0 5.2916665 5.2916668"
|
||||||
|
version="1.1"
|
||||||
|
id="svg8"
|
||||||
|
inkscape:version="0.92.2 2405546, 2018-03-11"
|
||||||
|
sodipodi:docname="IconFX.svg">
|
||||||
|
<defs
|
||||||
|
id="defs2" />
|
||||||
|
<sodipodi:namedview
|
||||||
|
id="base"
|
||||||
|
pagecolor="#353535"
|
||||||
|
bordercolor="#666666"
|
||||||
|
borderopacity="1.0"
|
||||||
|
inkscape:pageopacity="0"
|
||||||
|
inkscape:pageshadow="2"
|
||||||
|
inkscape:zoom="42.15"
|
||||||
|
inkscape:cx="31.643198"
|
||||||
|
inkscape:cy="20.391101"
|
||||||
|
inkscape:document-units="px"
|
||||||
|
inkscape:current-layer="layer1"
|
||||||
|
showgrid="true"
|
||||||
|
units="px"
|
||||||
|
inkscape:window-width="3840"
|
||||||
|
inkscape:window-height="2079"
|
||||||
|
inkscape:window-x="0"
|
||||||
|
inkscape:window-y="40"
|
||||||
|
inkscape:window-maximized="1"
|
||||||
|
gridtolerance="10"
|
||||||
|
showguides="false"
|
||||||
|
objecttolerance="17">
|
||||||
|
<inkscape:grid
|
||||||
|
type="xygrid"
|
||||||
|
id="grid817"
|
||||||
|
empspacing="0"
|
||||||
|
spacingx="0.52916666"
|
||||||
|
spacingy="0.52916666"
|
||||||
|
visible="true" />
|
||||||
|
</sodipodi:namedview>
|
||||||
|
<metadata
|
||||||
|
id="metadata5">
|
||||||
|
<rdf:RDF>
|
||||||
|
<cc:Work
|
||||||
|
rdf:about="">
|
||||||
|
<dc:format>image/svg+xml</dc:format>
|
||||||
|
<dc:type
|
||||||
|
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
|
||||||
|
<dc:title></dc:title>
|
||||||
|
</cc:Work>
|
||||||
|
</rdf:RDF>
|
||||||
|
</metadata>
|
||||||
|
<g
|
||||||
|
inkscape:label="Layer 1"
|
||||||
|
inkscape:groupmode="layer"
|
||||||
|
id="layer1"
|
||||||
|
transform="translate(0,-291.70832)">
|
||||||
|
<g
|
||||||
|
aria-label="fx"
|
||||||
|
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:5.17202616px;line-height:1.25;font-family:'Noto Serif';-inkscape-font-specification:'Noto Serif';letter-spacing:0px;word-spacing:0px;fill:#fffffa;fill-opacity:1;stroke:none;stroke-width:0.96975476"
|
||||||
|
id="text5280">
|
||||||
|
<path
|
||||||
|
d="m 0.31713132,296.97813 q -0.0775804,0 -0.16033281,-0.0155 -0.08792445,-0.0104 -0.13964471,-0.0259 l 0.04654823,-0.23792 q 0.04137621,0.0103 0.11378458,0.0207 0.0672363,0.0155 0.12412863,0.0155 0.25342928,0 0.39824601,-0.21723 0.13964471,-0.21722 0.25342928,-0.73442 L 1.4963533,293.25945 H 1.0256989 l 0.031032,-0.1862 0.4965145,-0.10861 0.056892,-0.28446 q 0.082752,-0.43962 0.3206656,-0.68271 0.2379132,-0.24308 0.6620193,-0.24308 0.3310097,0 0.4965145,0.10861 0.1706769,0.10344 0.1706769,0.27412 0,0.17067 -0.1137846,0.25343 -0.1086125,0.0827 -0.3154936,0.0827 0,-0.19654 -0.05172,-0.33618 -0.05172,-0.14482 -0.2120531,-0.14482 -0.191365,0 -0.2948055,0.16033 -0.1034405,0.15516 -0.1655048,0.481 l -0.067236,0.33101 H 2.613511 L 2.556619,293.2594 H 1.9773517 l -0.5378907,2.51877 q -0.098269,0.46031 -0.2534293,0.71891 -0.1551608,0.26378 -0.37238587,0.37239 -0.2172251,0.10861 -0.49651451,0.10861 z"
|
||||||
|
style="font-style:italic;font-variant:normal;font-weight:normal;font-stretch:normal;font-family:'Noto Serif';-inkscape-font-specification:'Noto Serif Italic';fill:#fffffa;fill-opacity:1;stroke-width:0.96975476"
|
||||||
|
id="path5282"
|
||||||
|
inkscape:connector-curvature="0" />
|
||||||
|
<path
|
||||||
|
d="m 2.28436,295.73685 0.056892,-0.21723 h 0.067236 q 0.098269,0 0.1706769,-0.0259 0.07758,-0.0259 0.1603328,-0.10344 0.082752,-0.0776 0.206881,-0.22757 l 0.6620194,-0.80166 -0.3361817,-0.80684 q -0.093097,-0.2224 -0.1603328,-0.2948 -0.062064,-0.0776 -0.2120531,-0.0776 h -0.067236 l 0.041376,-0.21723 H 3.56185 l 0.3930739,1.04475 0.6878795,-1.04475 h 0.6361592 l -0.056892,0.21723 h -0.067236 q -0.098268,0 -0.1758489,0.031 -0.07758,0.031 -0.1603328,0.11378 -0.082752,0.0776 -0.201709,0.22757 l -0.5430628,0.69823 0.3568698,0.89476 q 0.082752,0.22757 0.1499888,0.29997 0.072408,0.0724 0.2223971,0.0724 h 0.067236 l -0.041376,0.21723 H 4.1359454 L 3.7170112,294.599 2.9412073,295.73685 Z"
|
||||||
|
style="font-style:italic;font-variant:normal;font-weight:normal;font-stretch:normal;font-family:'Noto Serif';-inkscape-font-specification:'Noto Serif Italic';fill:#fffffa;fill-opacity:1;stroke-width:0.96975476"
|
||||||
|
id="path5284"
|
||||||
|
inkscape:connector-curvature="0" />
|
||||||
|
</g>
|
||||||
|
</g>
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 4.4 KiB |
74
Editor/resources/IconForward.svg
Normal file
@@ -0,0 +1,74 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||||
|
<!-- Created with Inkscape (http://www.inkscape.org/) -->
|
||||||
|
|
||||||
|
<svg
|
||||||
|
xmlns:dc="http://purl.org/dc/elements/1.1/"
|
||||||
|
xmlns:cc="http://creativecommons.org/ns#"
|
||||||
|
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
|
||||||
|
xmlns:svg="http://www.w3.org/2000/svg"
|
||||||
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
|
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||||
|
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||||
|
width="20"
|
||||||
|
height="20"
|
||||||
|
viewBox="0 0 5.2916665 5.2916669"
|
||||||
|
id="svg2"
|
||||||
|
version="1.1"
|
||||||
|
inkscape:version="0.92.2 2405546, 2018-03-11"
|
||||||
|
sodipodi:docname="IconForward.svg">
|
||||||
|
<defs
|
||||||
|
id="defs4" />
|
||||||
|
<sodipodi:namedview
|
||||||
|
id="base"
|
||||||
|
pagecolor="#393939"
|
||||||
|
bordercolor="#666666"
|
||||||
|
borderopacity="1.0"
|
||||||
|
inkscape:pageopacity="0"
|
||||||
|
inkscape:pageshadow="2"
|
||||||
|
inkscape:zoom="39.383707"
|
||||||
|
inkscape:cx="6.3383887"
|
||||||
|
inkscape:cy="7.7203454"
|
||||||
|
inkscape:document-units="px"
|
||||||
|
inkscape:current-layer="layer1"
|
||||||
|
showgrid="true"
|
||||||
|
units="px"
|
||||||
|
inkscape:window-width="3840"
|
||||||
|
inkscape:window-height="2079"
|
||||||
|
inkscape:window-x="0"
|
||||||
|
inkscape:window-y="40"
|
||||||
|
inkscape:window-maximized="1"
|
||||||
|
showborder="true"
|
||||||
|
objecttolerance="4"
|
||||||
|
gridtolerance="4"
|
||||||
|
guidetolerance="5">
|
||||||
|
<inkscape:grid
|
||||||
|
type="xygrid"
|
||||||
|
id="grid4173"
|
||||||
|
empspacing="1"
|
||||||
|
visible="true" />
|
||||||
|
</sodipodi:namedview>
|
||||||
|
<metadata
|
||||||
|
id="metadata7">
|
||||||
|
<rdf:RDF>
|
||||||
|
<cc:Work
|
||||||
|
rdf:about="">
|
||||||
|
<dc:format>image/svg+xml</dc:format>
|
||||||
|
<dc:type
|
||||||
|
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
|
||||||
|
<dc:title></dc:title>
|
||||||
|
</cc:Work>
|
||||||
|
</rdf:RDF>
|
||||||
|
</metadata>
|
||||||
|
<g
|
||||||
|
inkscape:label="Layer 1"
|
||||||
|
inkscape:groupmode="layer"
|
||||||
|
id="layer1"
|
||||||
|
transform="translate(0,-291.70832)">
|
||||||
|
<path
|
||||||
|
style="fill:#ffffff;fill-opacity:1;stroke:none;stroke-width:0.26458332px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
|
||||||
|
d="m 5.2916667,294.35415 -2.6458333,-2.64583 v 1.5875 H 0 v 1.85208 h 2.6458334 v 1.85209 z"
|
||||||
|
id="path841"
|
||||||
|
inkscape:connector-curvature="0"
|
||||||
|
sodipodi:nodetypes="cccccccc" />
|
||||||
|
</g>
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 2.2 KiB |
74
Editor/resources/IconForwardDisabled.svg
Normal file
@@ -0,0 +1,74 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||||
|
<!-- Created with Inkscape (http://www.inkscape.org/) -->
|
||||||
|
|
||||||
|
<svg
|
||||||
|
xmlns:dc="http://purl.org/dc/elements/1.1/"
|
||||||
|
xmlns:cc="http://creativecommons.org/ns#"
|
||||||
|
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
|
||||||
|
xmlns:svg="http://www.w3.org/2000/svg"
|
||||||
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
|
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||||
|
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||||
|
width="20"
|
||||||
|
height="20"
|
||||||
|
viewBox="0 0 5.2916665 5.2916669"
|
||||||
|
id="svg2"
|
||||||
|
version="1.1"
|
||||||
|
inkscape:version="0.92.2 2405546, 2018-03-11"
|
||||||
|
sodipodi:docname="IconForwardDisabled.svg">
|
||||||
|
<defs
|
||||||
|
id="defs4" />
|
||||||
|
<sodipodi:namedview
|
||||||
|
id="base"
|
||||||
|
pagecolor="#393939"
|
||||||
|
bordercolor="#666666"
|
||||||
|
borderopacity="1.0"
|
||||||
|
inkscape:pageopacity="0"
|
||||||
|
inkscape:pageshadow="2"
|
||||||
|
inkscape:zoom="39.383707"
|
||||||
|
inkscape:cx="6.3383887"
|
||||||
|
inkscape:cy="7.7203454"
|
||||||
|
inkscape:document-units="px"
|
||||||
|
inkscape:current-layer="layer1"
|
||||||
|
showgrid="true"
|
||||||
|
units="px"
|
||||||
|
inkscape:window-width="3840"
|
||||||
|
inkscape:window-height="2079"
|
||||||
|
inkscape:window-x="0"
|
||||||
|
inkscape:window-y="40"
|
||||||
|
inkscape:window-maximized="1"
|
||||||
|
showborder="true"
|
||||||
|
objecttolerance="4"
|
||||||
|
gridtolerance="4"
|
||||||
|
guidetolerance="5">
|
||||||
|
<inkscape:grid
|
||||||
|
type="xygrid"
|
||||||
|
id="grid4173"
|
||||||
|
empspacing="1"
|
||||||
|
visible="true" />
|
||||||
|
</sodipodi:namedview>
|
||||||
|
<metadata
|
||||||
|
id="metadata7">
|
||||||
|
<rdf:RDF>
|
||||||
|
<cc:Work
|
||||||
|
rdf:about="">
|
||||||
|
<dc:format>image/svg+xml</dc:format>
|
||||||
|
<dc:type
|
||||||
|
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
|
||||||
|
<dc:title></dc:title>
|
||||||
|
</cc:Work>
|
||||||
|
</rdf:RDF>
|
||||||
|
</metadata>
|
||||||
|
<g
|
||||||
|
inkscape:label="Layer 1"
|
||||||
|
inkscape:groupmode="layer"
|
||||||
|
id="layer1"
|
||||||
|
transform="translate(0,-291.70832)">
|
||||||
|
<path
|
||||||
|
style="fill:#ffffff;fill-opacity:0.39170507;stroke:none;stroke-width:0.26458332px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
|
||||||
|
d="m 5.2916667,294.35415 -2.6458333,-2.64583 v 1.5875 H 0 v 1.85208 h 2.6458334 v 1.85209 z"
|
||||||
|
id="path841"
|
||||||
|
inkscape:connector-curvature="0"
|
||||||
|
sodipodi:nodetypes="cccccccc" />
|
||||||
|
</g>
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 2.2 KiB |
74
Editor/resources/IconGroup.svg
Normal file
@@ -0,0 +1,74 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||||
|
<!-- Created with Inkscape (http://www.inkscape.org/) -->
|
||||||
|
|
||||||
|
<svg
|
||||||
|
xmlns:dc="http://purl.org/dc/elements/1.1/"
|
||||||
|
xmlns:cc="http://creativecommons.org/ns#"
|
||||||
|
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
|
||||||
|
xmlns:svg="http://www.w3.org/2000/svg"
|
||||||
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
|
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||||
|
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||||
|
width="16"
|
||||||
|
height="16"
|
||||||
|
viewBox="0 0 4.2333332 4.2333335"
|
||||||
|
id="svg2"
|
||||||
|
version="1.1"
|
||||||
|
inkscape:version="0.91+devel+osxmenu r12922"
|
||||||
|
sodipodi:docname="IconSoundGroup.svg">
|
||||||
|
<defs
|
||||||
|
id="defs4" />
|
||||||
|
<sodipodi:namedview
|
||||||
|
id="base"
|
||||||
|
pagecolor="#393939"
|
||||||
|
bordercolor="#666666"
|
||||||
|
borderopacity="1.0"
|
||||||
|
inkscape:pageopacity="0"
|
||||||
|
inkscape:pageshadow="2"
|
||||||
|
inkscape:zoom="19.66"
|
||||||
|
inkscape:cx="6.046968"
|
||||||
|
inkscape:cy="6.9530957"
|
||||||
|
inkscape:document-units="px"
|
||||||
|
inkscape:current-layer="layer1"
|
||||||
|
showgrid="true"
|
||||||
|
units="px"
|
||||||
|
inkscape:window-width="1260"
|
||||||
|
inkscape:window-height="787"
|
||||||
|
inkscape:window-x="231"
|
||||||
|
inkscape:window-y="82"
|
||||||
|
inkscape:window-maximized="0"
|
||||||
|
showborder="true"
|
||||||
|
objecttolerance="4"
|
||||||
|
gridtolerance="4"
|
||||||
|
guidetolerance="5">
|
||||||
|
<inkscape:grid
|
||||||
|
type="xygrid"
|
||||||
|
id="grid4173"
|
||||||
|
empspacing="1"
|
||||||
|
visible="true" />
|
||||||
|
</sodipodi:namedview>
|
||||||
|
<metadata
|
||||||
|
id="metadata7">
|
||||||
|
<rdf:RDF>
|
||||||
|
<cc:Work
|
||||||
|
rdf:about="">
|
||||||
|
<dc:format>image/svg+xml</dc:format>
|
||||||
|
<dc:type
|
||||||
|
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
|
||||||
|
<dc:title></dc:title>
|
||||||
|
</cc:Work>
|
||||||
|
</rdf:RDF>
|
||||||
|
</metadata>
|
||||||
|
<g
|
||||||
|
inkscape:label="Layer 1"
|
||||||
|
inkscape:groupmode="layer"
|
||||||
|
id="layer1"
|
||||||
|
transform="translate(0,-292.76665)">
|
||||||
|
<path
|
||||||
|
style="opacity:1;fill:#fbd365;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1.67643285;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
|
||||||
|
d="m 1.3229167,293.04538 c 0.2645833,0 0.5291666,0.25044 0.5291666,0.51502 l 0,0.26458 1.8488138,0.0102 c 0.3165926,0.002 0.5239173,0.20975 0.5245413,0.52471 l 0.00313,1.57936 c 6.239e-4,0.31495 -0.2079439,0.53411 -0.5245413,0.53411 l -3.17666623,0 C 0.21076252,296.47339 0,296.2566 0,295.94165 c 4.054e-5,-0.82258 0,-2.38125 0,-2.38125 0,-0.26458 0.26458333,-0.51612 0.52916667,-0.51612 z"
|
||||||
|
id="rect4141"
|
||||||
|
inkscape:connector-curvature="0"
|
||||||
|
sodipodi:nodetypes="cccssssscccc" />
|
||||||
|
</g>
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 2.5 KiB |
104
Editor/resources/IconImport.svg
Normal file
@@ -0,0 +1,104 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||||
|
<!-- Created with Inkscape (http://www.inkscape.org/) -->
|
||||||
|
|
||||||
|
<svg
|
||||||
|
xmlns:dc="http://purl.org/dc/elements/1.1/"
|
||||||
|
xmlns:cc="http://creativecommons.org/ns#"
|
||||||
|
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
|
||||||
|
xmlns:svg="http://www.w3.org/2000/svg"
|
||||||
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
|
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||||
|
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||||
|
width="16"
|
||||||
|
height="16"
|
||||||
|
viewBox="0 0 4.2333332 4.2333335"
|
||||||
|
id="svg2"
|
||||||
|
version="1.1"
|
||||||
|
inkscape:version="0.91+devel+osxmenu r12922"
|
||||||
|
sodipodi:docname="IconImport.svg">
|
||||||
|
<defs
|
||||||
|
id="defs4" />
|
||||||
|
<sodipodi:namedview
|
||||||
|
id="base"
|
||||||
|
pagecolor="#2a2a2a"
|
||||||
|
bordercolor="#666666"
|
||||||
|
borderopacity="1.0"
|
||||||
|
inkscape:pageopacity="0"
|
||||||
|
inkscape:pageshadow="2"
|
||||||
|
inkscape:zoom="2"
|
||||||
|
inkscape:cx="9.0918787"
|
||||||
|
inkscape:cy="8.1216613"
|
||||||
|
inkscape:document-units="px"
|
||||||
|
inkscape:current-layer="layer1"
|
||||||
|
showgrid="true"
|
||||||
|
units="px"
|
||||||
|
inkscape:window-width="1260"
|
||||||
|
inkscape:window-height="863"
|
||||||
|
inkscape:window-x="365"
|
||||||
|
inkscape:window-y="83"
|
||||||
|
inkscape:window-maximized="0"
|
||||||
|
showborder="false"
|
||||||
|
objecttolerance="4"
|
||||||
|
gridtolerance="4"
|
||||||
|
guidetolerance="5">
|
||||||
|
<inkscape:grid
|
||||||
|
type="xygrid"
|
||||||
|
id="grid4173"
|
||||||
|
empspacing="1"
|
||||||
|
visible="false" />
|
||||||
|
</sodipodi:namedview>
|
||||||
|
<metadata
|
||||||
|
id="metadata7">
|
||||||
|
<rdf:RDF>
|
||||||
|
<cc:Work
|
||||||
|
rdf:about="">
|
||||||
|
<dc:format>image/svg+xml</dc:format>
|
||||||
|
<dc:type
|
||||||
|
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
|
||||||
|
<dc:title></dc:title>
|
||||||
|
</cc:Work>
|
||||||
|
</rdf:RDF>
|
||||||
|
</metadata>
|
||||||
|
<g
|
||||||
|
inkscape:label="Layer 1"
|
||||||
|
inkscape:groupmode="layer"
|
||||||
|
id="layer1"
|
||||||
|
transform="translate(0,-292.76665)">
|
||||||
|
<path
|
||||||
|
style="opacity:1;fill:#ff2ad4;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:0.99999994;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
|
||||||
|
d="m 1.984375,292.7713 a 2.1166665,2.1166665 0 0 0 -1.62935791,0.94258 l 1.62935791,0.94103 0,-1.88361 z"
|
||||||
|
id="path4824"
|
||||||
|
inkscape:connector-curvature="0" />
|
||||||
|
<path
|
||||||
|
style="opacity:1;fill:#d40000;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:0.99999994;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
|
||||||
|
d="m 2.2479248,292.77285 0,1.88309 1.6303914,-0.94154 a 2.1166665,2.1166665 0 0 0 -1.6303914,-0.94155 z"
|
||||||
|
id="path4822"
|
||||||
|
inkscape:connector-curvature="0" />
|
||||||
|
<path
|
||||||
|
style="opacity:1;fill:#6600ff;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:0.99999994;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
|
||||||
|
d="M 0.22375895,293.94281 A 2.1166665,2.1166665 0 0 0 0,294.88332 a 2.1166665,2.1166665 0 0 0 0.22479248,0.94102 l 1.62832432,-0.94051 -1.62935785,-0.94102 z"
|
||||||
|
id="path4820"
|
||||||
|
inkscape:connector-curvature="0" />
|
||||||
|
<path
|
||||||
|
style="opacity:1;fill:#ff6600;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:0.99999994;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
|
||||||
|
d="m 4.0095744,293.94332 -1.6288412,0.94051 1.6288412,0.94051 a 2.1166665,2.1166665 0 0 0 0.2237589,-0.94102 2.1166665,2.1166665 0 0 0 -0.2237589,-0.94 z"
|
||||||
|
id="path4818"
|
||||||
|
inkscape:connector-curvature="0" />
|
||||||
|
<path
|
||||||
|
style="opacity:1;fill:#ffcc00;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:0.99999994;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
|
||||||
|
d="m 2.2479248,295.11121 0,1.88412 a 2.1166665,2.1166665 0 0 0 1.6303914,-0.94258 l -1.6303914,-0.94154 z"
|
||||||
|
id="path4816"
|
||||||
|
inkscape:connector-curvature="0" />
|
||||||
|
<path
|
||||||
|
style="opacity:1;fill:#2ad4ff;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:0.99999994;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
|
||||||
|
d="m 1.984375,295.11276 -1.62884115,0.93999 a 2.1166665,2.1166665 0 0 0 1.62884115,0.94052 l 0,-1.88051 z"
|
||||||
|
id="path4782"
|
||||||
|
inkscape:connector-curvature="0" />
|
||||||
|
<circle
|
||||||
|
style="opacity:1;fill:#66ff00;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:0.26458332;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
|
||||||
|
id="path4826"
|
||||||
|
cx="2.1166668"
|
||||||
|
cy="294.88333"
|
||||||
|
r="1.2296628" />
|
||||||
|
</g>
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 4.6 KiB |
95
Editor/resources/IconKeymap.svg
Normal file
@@ -0,0 +1,95 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||||
|
<!-- Created with Inkscape (http://www.inkscape.org/) -->
|
||||||
|
|
||||||
|
<svg
|
||||||
|
xmlns:dc="http://purl.org/dc/elements/1.1/"
|
||||||
|
xmlns:cc="http://creativecommons.org/ns#"
|
||||||
|
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
|
||||||
|
xmlns:svg="http://www.w3.org/2000/svg"
|
||||||
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
|
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||||
|
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||||
|
width="16"
|
||||||
|
height="16"
|
||||||
|
viewBox="0 0 4.2333332 4.2333335"
|
||||||
|
id="svg2"
|
||||||
|
version="1.1"
|
||||||
|
inkscape:version="0.91+devel+osxmenu r12922"
|
||||||
|
sodipodi:docname="IconKeymap.svg">
|
||||||
|
<defs
|
||||||
|
id="defs4" />
|
||||||
|
<sodipodi:namedview
|
||||||
|
id="base"
|
||||||
|
pagecolor="#393939"
|
||||||
|
bordercolor="#666666"
|
||||||
|
borderopacity="1.0"
|
||||||
|
inkscape:pageopacity="0"
|
||||||
|
inkscape:pageshadow="2"
|
||||||
|
inkscape:zoom="22.528678"
|
||||||
|
inkscape:cx="6.3570002"
|
||||||
|
inkscape:cy="7.1823475"
|
||||||
|
inkscape:document-units="px"
|
||||||
|
inkscape:current-layer="layer1"
|
||||||
|
showgrid="true"
|
||||||
|
units="px"
|
||||||
|
inkscape:window-width="1260"
|
||||||
|
inkscape:window-height="787"
|
||||||
|
inkscape:window-x="0"
|
||||||
|
inkscape:window-y="23"
|
||||||
|
inkscape:window-maximized="0"
|
||||||
|
showborder="true"
|
||||||
|
objecttolerance="4"
|
||||||
|
gridtolerance="4"
|
||||||
|
guidetolerance="5">
|
||||||
|
<inkscape:grid
|
||||||
|
type="xygrid"
|
||||||
|
id="grid4173"
|
||||||
|
empspacing="1"
|
||||||
|
visible="true" />
|
||||||
|
</sodipodi:namedview>
|
||||||
|
<metadata
|
||||||
|
id="metadata7">
|
||||||
|
<rdf:RDF>
|
||||||
|
<cc:Work
|
||||||
|
rdf:about="">
|
||||||
|
<dc:format>image/svg+xml</dc:format>
|
||||||
|
<dc:type
|
||||||
|
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
|
||||||
|
<dc:title></dc:title>
|
||||||
|
</cc:Work>
|
||||||
|
</rdf:RDF>
|
||||||
|
</metadata>
|
||||||
|
<g
|
||||||
|
inkscape:label="Layer 1"
|
||||||
|
inkscape:groupmode="layer"
|
||||||
|
id="layer1"
|
||||||
|
transform="translate(0,-292.76665)">
|
||||||
|
<rect
|
||||||
|
style="opacity:1;fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:0.26458332;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
|
||||||
|
id="rect6472"
|
||||||
|
width="4.2333331"
|
||||||
|
height="3.1750097"
|
||||||
|
x="0"
|
||||||
|
y="293.29581" />
|
||||||
|
<path
|
||||||
|
style="fill:#ffffff;fill-rule:evenodd;stroke:none;stroke-width:0.26458332px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;fill-opacity:1"
|
||||||
|
d="m 0.26458333,293.5604 0,2.64583 0.79374997,0 0,-1.32291 -0.26458331,0 0,-1.32292 -0.52916666,0"
|
||||||
|
id="path6474"
|
||||||
|
inkscape:connector-curvature="0" />
|
||||||
|
<path
|
||||||
|
style="fill:#ffffff;fill-rule:evenodd;stroke:none;stroke-width:0.26458332px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;fill-opacity:1"
|
||||||
|
d="m 1.3229166,294.88332 0,1.32291 0.79375,0 0,-1.32291 -0.2645833,0 0,-1.32292 -0.2645833,0 0,1.32292 z"
|
||||||
|
id="path6476"
|
||||||
|
inkscape:connector-curvature="0" />
|
||||||
|
<path
|
||||||
|
style="fill:#ffffff;fill-rule:evenodd;stroke:none;stroke-width:0.26458332px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;fill-opacity:1"
|
||||||
|
d="m 2.38125,294.88332 0,1.32291 0.79375,0 0,-1.32291 0,-1.32292 -0.5291667,0 0,1.32292 z"
|
||||||
|
id="path6478"
|
||||||
|
inkscape:connector-curvature="0" />
|
||||||
|
<path
|
||||||
|
style="fill:#ffffff;fill-rule:evenodd;stroke:none;stroke-width:0.26458332px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;fill-opacity:1"
|
||||||
|
d="m 3.4395833,293.5604 0,2.64583 0.5291667,0 0,-2.64583 z"
|
||||||
|
id="path6480"
|
||||||
|
inkscape:connector-curvature="0" />
|
||||||
|
</g>
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 3.4 KiB |
110
Editor/resources/IconKill.svg
Normal file
@@ -0,0 +1,110 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||||
|
<!-- Created with Inkscape (http://www.inkscape.org/) -->
|
||||||
|
|
||||||
|
<svg
|
||||||
|
xmlns:dc="http://purl.org/dc/elements/1.1/"
|
||||||
|
xmlns:cc="http://creativecommons.org/ns#"
|
||||||
|
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
|
||||||
|
xmlns:svg="http://www.w3.org/2000/svg"
|
||||||
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
|
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||||
|
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||||
|
width="20"
|
||||||
|
height="20"
|
||||||
|
viewBox="0 0 5.2916665 5.2916668"
|
||||||
|
version="1.1"
|
||||||
|
id="svg8"
|
||||||
|
inkscape:version="0.92.2 2405546, 2018-03-11"
|
||||||
|
sodipodi:docname="IconKill.svg">
|
||||||
|
<defs
|
||||||
|
id="defs2" />
|
||||||
|
<sodipodi:namedview
|
||||||
|
id="base"
|
||||||
|
pagecolor="#353535"
|
||||||
|
bordercolor="#666666"
|
||||||
|
borderopacity="1.0"
|
||||||
|
inkscape:pageopacity="0"
|
||||||
|
inkscape:pageshadow="2"
|
||||||
|
inkscape:zoom="39.226909"
|
||||||
|
inkscape:cx="9.3355483"
|
||||||
|
inkscape:cy="10.583863"
|
||||||
|
inkscape:document-units="px"
|
||||||
|
inkscape:current-layer="layer1"
|
||||||
|
showgrid="true"
|
||||||
|
units="px"
|
||||||
|
inkscape:window-width="3840"
|
||||||
|
inkscape:window-height="2079"
|
||||||
|
inkscape:window-x="0"
|
||||||
|
inkscape:window-y="40"
|
||||||
|
inkscape:window-maximized="1"
|
||||||
|
gridtolerance="10"
|
||||||
|
showguides="false">
|
||||||
|
<inkscape:grid
|
||||||
|
type="xygrid"
|
||||||
|
id="grid817"
|
||||||
|
empspacing="0"
|
||||||
|
spacingx="0.52916666"
|
||||||
|
spacingy="0.52916666"
|
||||||
|
visible="false" />
|
||||||
|
</sodipodi:namedview>
|
||||||
|
<metadata
|
||||||
|
id="metadata5">
|
||||||
|
<rdf:RDF>
|
||||||
|
<cc:Work
|
||||||
|
rdf:about="">
|
||||||
|
<dc:format>image/svg+xml</dc:format>
|
||||||
|
<dc:type
|
||||||
|
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
|
||||||
|
<dc:title></dc:title>
|
||||||
|
</cc:Work>
|
||||||
|
</rdf:RDF>
|
||||||
|
</metadata>
|
||||||
|
<g
|
||||||
|
inkscape:label="Layer 1"
|
||||||
|
inkscape:groupmode="layer"
|
||||||
|
id="layer1"
|
||||||
|
transform="translate(0,-291.70832)">
|
||||||
|
<path
|
||||||
|
style="fill:#fffff8;fill-opacity:1;stroke:#000000;stroke-width:0.30217573px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
|
||||||
|
d="m 1.4046674,296.70833 v -1.17708 c 0,0 -1.24116588,-0.58856 -1.24116588,-1.1771 0,-0.58853 0,-2.35417 2.48233178,-2.35417 2.4823318,0 2.4823318,1.76564 2.4823318,2.35417 0,0.58854 -1.2411659,1.1771 -1.2411659,1.1771 v 1.17708 z"
|
||||||
|
id="path842"
|
||||||
|
inkscape:connector-curvature="0" />
|
||||||
|
<path
|
||||||
|
style="fill:#000006;fill-opacity:1;stroke:none;stroke-width:0.79053128;stroke-linecap:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:0.49803922"
|
||||||
|
id="path844"
|
||||||
|
sodipodi:type="arc"
|
||||||
|
sodipodi:cx="1.6969496"
|
||||||
|
sodipodi:cy="294.08957"
|
||||||
|
sodipodi:rx="0.71268904"
|
||||||
|
sodipodi:ry="0.65353703"
|
||||||
|
sodipodi:start="0"
|
||||||
|
sodipodi:end="5.866374"
|
||||||
|
d="m 2.4096386,294.08957 a 0.71268904,0.65353703 0 0 1 -0.6385591,0.64999 0.71268904,0.65353703 0 0 1 -0.7713978,-0.51477 0.71268904,0.65353703 0 0 1 0.4780863,-0.75708 0.71268904,0.65353703 0 0 1 0.8708534,0.35728 l -0.6516718,0.26458 z" />
|
||||||
|
<path
|
||||||
|
d="m 4.2943505,294.08957 a 0.71268904,0.65353703 0 0 1 -0.6385591,0.64999 0.71268904,0.65353703 0 0 1 -0.7713978,-0.51477 0.71268904,0.65353703 0 0 1 0.4780862,-0.75708 0.71268904,0.65353703 0 0 1 0.8708535,0.35728 l -0.6516718,0.26458 z"
|
||||||
|
sodipodi:end="5.866374"
|
||||||
|
sodipodi:start="0"
|
||||||
|
sodipodi:ry="0.65353703"
|
||||||
|
sodipodi:rx="0.71268904"
|
||||||
|
sodipodi:cy="294.08957"
|
||||||
|
sodipodi:cx="3.5816615"
|
||||||
|
sodipodi:type="arc"
|
||||||
|
id="path846"
|
||||||
|
style="fill:#000006;fill-opacity:1;stroke:none;stroke-width:0.79053128;stroke-linecap:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:0.49803922" />
|
||||||
|
<path
|
||||||
|
style="fill:none;stroke:#000000;stroke-width:0.29107958px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
|
||||||
|
d="m 2.6458333,295.41249 v 1.28091"
|
||||||
|
id="path848"
|
||||||
|
inkscape:connector-curvature="0" />
|
||||||
|
<path
|
||||||
|
style="fill:none;stroke:#000000;stroke-width:0.29184496px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
|
||||||
|
d="m 2.0289823,295.41249 v 1.28766"
|
||||||
|
id="path850"
|
||||||
|
inkscape:connector-curvature="0" />
|
||||||
|
<path
|
||||||
|
style="fill:none;stroke:#000000;stroke-width:0.29107958px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
|
||||||
|
d="m 3.2694292,295.41249 v 1.28091"
|
||||||
|
id="path852"
|
||||||
|
inkscape:connector-curvature="0" />
|
||||||
|
</g>
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 4.3 KiB |
83
Editor/resources/IconLayers.svg
Normal file
@@ -0,0 +1,83 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||||
|
<!-- Created with Inkscape (http://www.inkscape.org/) -->
|
||||||
|
|
||||||
|
<svg
|
||||||
|
xmlns:dc="http://purl.org/dc/elements/1.1/"
|
||||||
|
xmlns:cc="http://creativecommons.org/ns#"
|
||||||
|
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
|
||||||
|
xmlns:svg="http://www.w3.org/2000/svg"
|
||||||
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
|
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||||
|
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||||
|
width="16"
|
||||||
|
height="16"
|
||||||
|
viewBox="0 0 4.2333332 4.2333335"
|
||||||
|
id="svg2"
|
||||||
|
version="1.1"
|
||||||
|
inkscape:version="0.92.2 2405546, 2018-03-11"
|
||||||
|
sodipodi:docname="IconLayers.svg">
|
||||||
|
<defs
|
||||||
|
id="defs4" />
|
||||||
|
<sodipodi:namedview
|
||||||
|
id="base"
|
||||||
|
pagecolor="#393939"
|
||||||
|
bordercolor="#666666"
|
||||||
|
borderopacity="1.0"
|
||||||
|
inkscape:pageopacity="0"
|
||||||
|
inkscape:pageshadow="2"
|
||||||
|
inkscape:zoom="4.92"
|
||||||
|
inkscape:cx="-13.575223"
|
||||||
|
inkscape:cy="7.1823475"
|
||||||
|
inkscape:document-units="px"
|
||||||
|
inkscape:current-layer="layer1"
|
||||||
|
showgrid="true"
|
||||||
|
units="px"
|
||||||
|
inkscape:window-width="1260"
|
||||||
|
inkscape:window-height="787"
|
||||||
|
inkscape:window-x="1749"
|
||||||
|
inkscape:window-y="677"
|
||||||
|
inkscape:window-maximized="0"
|
||||||
|
showborder="false"
|
||||||
|
objecttolerance="4"
|
||||||
|
gridtolerance="4"
|
||||||
|
guidetolerance="5">
|
||||||
|
<inkscape:grid
|
||||||
|
type="xygrid"
|
||||||
|
id="grid4173"
|
||||||
|
empspacing="1"
|
||||||
|
visible="false" />
|
||||||
|
</sodipodi:namedview>
|
||||||
|
<metadata
|
||||||
|
id="metadata7">
|
||||||
|
<rdf:RDF>
|
||||||
|
<cc:Work
|
||||||
|
rdf:about="">
|
||||||
|
<dc:format>image/svg+xml</dc:format>
|
||||||
|
<dc:type
|
||||||
|
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
|
||||||
|
<dc:title />
|
||||||
|
</cc:Work>
|
||||||
|
</rdf:RDF>
|
||||||
|
</metadata>
|
||||||
|
<g
|
||||||
|
inkscape:label="Layer 1"
|
||||||
|
inkscape:groupmode="layer"
|
||||||
|
id="layer1"
|
||||||
|
transform="translate(0,-292.76665)">
|
||||||
|
<path
|
||||||
|
style="fill:#ff0066;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:0.26458332px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
|
||||||
|
d="m 0.26458333,293.29581 0,0.79375 3.70416667,0 0,-0.79375 z"
|
||||||
|
id="path7056"
|
||||||
|
inkscape:connector-curvature="0" />
|
||||||
|
<path
|
||||||
|
inkscape:connector-curvature="0"
|
||||||
|
id="path7058"
|
||||||
|
d="m 0.26458333,294.35415 0,0.79375 3.70416667,0 0,-0.79375 z"
|
||||||
|
style="fill:#ffcc00;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:0.26458332px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" />
|
||||||
|
<path
|
||||||
|
style="fill:#00aad4;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:0.26458332px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
|
||||||
|
d="m 0.26458333,295.41248 0,0.79375 3.70416667,0 0,-0.79375 z"
|
||||||
|
id="path7060"
|
||||||
|
inkscape:connector-curvature="0" />
|
||||||
|
</g>
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 2.7 KiB |
80
Editor/resources/IconNew.svg
Normal file
@@ -0,0 +1,80 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||||
|
<!-- Created with Inkscape (http://www.inkscape.org/) -->
|
||||||
|
|
||||||
|
<svg
|
||||||
|
xmlns:dc="http://purl.org/dc/elements/1.1/"
|
||||||
|
xmlns:cc="http://creativecommons.org/ns#"
|
||||||
|
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
|
||||||
|
xmlns:svg="http://www.w3.org/2000/svg"
|
||||||
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
|
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||||
|
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||||
|
width="16"
|
||||||
|
height="16"
|
||||||
|
viewBox="0 0 4.2333332 4.2333335"
|
||||||
|
id="svg2"
|
||||||
|
version="1.1"
|
||||||
|
inkscape:version="0.91+devel+osxmenu r12922"
|
||||||
|
sodipodi:docname="IconNew.svg">
|
||||||
|
<defs
|
||||||
|
id="defs4" />
|
||||||
|
<sodipodi:namedview
|
||||||
|
id="base"
|
||||||
|
pagecolor="#393939"
|
||||||
|
bordercolor="#666666"
|
||||||
|
borderopacity="1.0"
|
||||||
|
inkscape:pageopacity="0"
|
||||||
|
inkscape:pageshadow="2"
|
||||||
|
inkscape:zoom="4.3015958"
|
||||||
|
inkscape:cx="-1.383522"
|
||||||
|
inkscape:cy="20.267081"
|
||||||
|
inkscape:document-units="px"
|
||||||
|
inkscape:current-layer="layer1"
|
||||||
|
showgrid="true"
|
||||||
|
units="px"
|
||||||
|
inkscape:window-width="1260"
|
||||||
|
inkscape:window-height="787"
|
||||||
|
inkscape:window-x="172"
|
||||||
|
inkscape:window-y="33"
|
||||||
|
inkscape:window-maximized="0"
|
||||||
|
showborder="false"
|
||||||
|
objecttolerance="4"
|
||||||
|
gridtolerance="4"
|
||||||
|
guidetolerance="5">
|
||||||
|
<inkscape:grid
|
||||||
|
type="xygrid"
|
||||||
|
id="grid4173"
|
||||||
|
empspacing="1"
|
||||||
|
visible="false" />
|
||||||
|
</sodipodi:namedview>
|
||||||
|
<metadata
|
||||||
|
id="metadata7">
|
||||||
|
<rdf:RDF>
|
||||||
|
<cc:Work
|
||||||
|
rdf:about="">
|
||||||
|
<dc:format>image/svg+xml</dc:format>
|
||||||
|
<dc:type
|
||||||
|
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
|
||||||
|
<dc:title></dc:title>
|
||||||
|
</cc:Work>
|
||||||
|
</rdf:RDF>
|
||||||
|
</metadata>
|
||||||
|
<g
|
||||||
|
inkscape:label="Layer 1"
|
||||||
|
inkscape:groupmode="layer"
|
||||||
|
id="layer1"
|
||||||
|
transform="translate(0,-292.76665)">
|
||||||
|
<path
|
||||||
|
style="fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:0.26458332px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
|
||||||
|
d="m 3.4395833,292.76665 0,4.23333 -2.6458333,0 c 0,-1.14653 0,-2.02847 0,-3.175 l 1.0583333,-1.05833 z"
|
||||||
|
id="path4171"
|
||||||
|
inkscape:connector-curvature="0"
|
||||||
|
sodipodi:nodetypes="cccccc" />
|
||||||
|
<path
|
||||||
|
style="fill:none;fill-rule:evenodd;stroke:#c7c7c7;stroke-width:0.26458332px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
|
||||||
|
d="m 0.79375,293.9564 1.1898162,0 0,-1.18975"
|
||||||
|
id="path4182"
|
||||||
|
inkscape:connector-curvature="0"
|
||||||
|
sodipodi:nodetypes="ccc" />
|
||||||
|
</g>
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 2.5 KiB |
86
Editor/resources/IconNewADSR.svg
Normal file
@@ -0,0 +1,86 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||||
|
<!-- Created with Inkscape (http://www.inkscape.org/) -->
|
||||||
|
|
||||||
|
<svg
|
||||||
|
xmlns:dc="http://purl.org/dc/elements/1.1/"
|
||||||
|
xmlns:cc="http://creativecommons.org/ns#"
|
||||||
|
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
|
||||||
|
xmlns:svg="http://www.w3.org/2000/svg"
|
||||||
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
|
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||||
|
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||||
|
width="16"
|
||||||
|
height="16"
|
||||||
|
viewBox="0 0 4.2333332 4.2333335"
|
||||||
|
id="svg2"
|
||||||
|
version="1.1"
|
||||||
|
inkscape:version="0.92.2 2405546, 2018-03-11"
|
||||||
|
sodipodi:docname="IconNewADSR.svg">
|
||||||
|
<sodipodi:namedview
|
||||||
|
id="base"
|
||||||
|
pagecolor="#393939"
|
||||||
|
bordercolor="#666666"
|
||||||
|
borderopacity="1.0"
|
||||||
|
inkscape:pageopacity="0"
|
||||||
|
inkscape:pageshadow="2"
|
||||||
|
inkscape:zoom="30.086227"
|
||||||
|
inkscape:cx="7.2902772"
|
||||||
|
inkscape:cy="8.0995259"
|
||||||
|
inkscape:document-units="px"
|
||||||
|
inkscape:current-layer="layer1"
|
||||||
|
showgrid="true"
|
||||||
|
units="px"
|
||||||
|
inkscape:window-width="1260"
|
||||||
|
inkscape:window-height="787"
|
||||||
|
inkscape:window-x="341"
|
||||||
|
inkscape:window-y="1113"
|
||||||
|
inkscape:window-maximized="0"
|
||||||
|
showborder="false"
|
||||||
|
objecttolerance="4"
|
||||||
|
gridtolerance="4"
|
||||||
|
guidetolerance="5">
|
||||||
|
<inkscape:grid
|
||||||
|
visible="true"
|
||||||
|
empspacing="1"
|
||||||
|
id="grid4173"
|
||||||
|
type="xygrid" />
|
||||||
|
</sodipodi:namedview>
|
||||||
|
<defs
|
||||||
|
id="defs4" />
|
||||||
|
<metadata
|
||||||
|
id="metadata7">
|
||||||
|
<rdf:RDF>
|
||||||
|
<cc:Work
|
||||||
|
rdf:about="">
|
||||||
|
<dc:format>image/svg+xml</dc:format>
|
||||||
|
<dc:type
|
||||||
|
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
|
||||||
|
<dc:title></dc:title>
|
||||||
|
</cc:Work>
|
||||||
|
</rdf:RDF>
|
||||||
|
</metadata>
|
||||||
|
<g
|
||||||
|
transform="translate(0,-292.76665)"
|
||||||
|
id="layer1"
|
||||||
|
inkscape:groupmode="layer"
|
||||||
|
inkscape:label="Layer 1">
|
||||||
|
<rect
|
||||||
|
style="fill:#ff6600;fill-opacity:1;stroke:none;stroke-width:0.39687499;stroke-linecap:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;paint-order:normal"
|
||||||
|
id="rect1235"
|
||||||
|
width="3.7041667"
|
||||||
|
height="3.7041805"
|
||||||
|
x="0.26458335"
|
||||||
|
y="293.03122" />
|
||||||
|
<path
|
||||||
|
style="fill:none;stroke:#000000;stroke-width:0.5291667;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
|
||||||
|
d="M 0.26458333,296.7354 1.0583334,293.47246 1.5875,294.35415 H 2.9104167 L 3.96875,296.7354"
|
||||||
|
id="path1834"
|
||||||
|
inkscape:connector-curvature="0"
|
||||||
|
sodipodi:nodetypes="ccccc" />
|
||||||
|
<path
|
||||||
|
inkscape:connector-curvature="0"
|
||||||
|
id="path5323"
|
||||||
|
style="fill:#ff0000;fill-rule:evenodd;stroke:#df0000;stroke-width:0.26458332;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
|
||||||
|
d="m 2.8386428,295.34071 0.9362114,0.93622 m -0.9362104,-10e-6 0.9362094,-0.9362 m -1.1301062,0.4681 H 3.96875 m -0.6620015,0.662 v -1.324" />
|
||||||
|
</g>
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 2.9 KiB |
92
Editor/resources/IconNewCurve.svg
Normal file
@@ -0,0 +1,92 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||||
|
<!-- Created with Inkscape (http://www.inkscape.org/) -->
|
||||||
|
|
||||||
|
<svg
|
||||||
|
xmlns:dc="http://purl.org/dc/elements/1.1/"
|
||||||
|
xmlns:cc="http://creativecommons.org/ns#"
|
||||||
|
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
|
||||||
|
xmlns:svg="http://www.w3.org/2000/svg"
|
||||||
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
|
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||||
|
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||||
|
width="16"
|
||||||
|
height="16"
|
||||||
|
viewBox="0 0 4.2333332 4.2333335"
|
||||||
|
id="svg2"
|
||||||
|
version="1.1"
|
||||||
|
inkscape:version="0.92.2 2405546, 2018-03-11"
|
||||||
|
sodipodi:docname="IconNewCurve.svg">
|
||||||
|
<sodipodi:namedview
|
||||||
|
id="base"
|
||||||
|
pagecolor="#393939"
|
||||||
|
bordercolor="#666666"
|
||||||
|
borderopacity="1.0"
|
||||||
|
inkscape:pageopacity="0"
|
||||||
|
inkscape:pageshadow="2"
|
||||||
|
inkscape:zoom="30.086227"
|
||||||
|
inkscape:cx="8.2484922"
|
||||||
|
inkscape:cy="9.4290379"
|
||||||
|
inkscape:document-units="px"
|
||||||
|
inkscape:current-layer="layer1"
|
||||||
|
showgrid="true"
|
||||||
|
units="px"
|
||||||
|
inkscape:window-width="1260"
|
||||||
|
inkscape:window-height="787"
|
||||||
|
inkscape:window-x="459"
|
||||||
|
inkscape:window-y="172"
|
||||||
|
inkscape:window-maximized="0"
|
||||||
|
showborder="false"
|
||||||
|
objecttolerance="4"
|
||||||
|
gridtolerance="4"
|
||||||
|
guidetolerance="5">
|
||||||
|
<inkscape:grid
|
||||||
|
visible="true"
|
||||||
|
empspacing="1"
|
||||||
|
id="grid4173"
|
||||||
|
type="xygrid" />
|
||||||
|
</sodipodi:namedview>
|
||||||
|
<defs
|
||||||
|
id="defs4" />
|
||||||
|
<metadata
|
||||||
|
id="metadata7">
|
||||||
|
<rdf:RDF>
|
||||||
|
<cc:Work
|
||||||
|
rdf:about="">
|
||||||
|
<dc:format>image/svg+xml</dc:format>
|
||||||
|
<dc:type
|
||||||
|
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
|
||||||
|
<dc:title></dc:title>
|
||||||
|
</cc:Work>
|
||||||
|
</rdf:RDF>
|
||||||
|
</metadata>
|
||||||
|
<g
|
||||||
|
transform="translate(0,-292.76665)"
|
||||||
|
id="layer1"
|
||||||
|
inkscape:groupmode="layer"
|
||||||
|
inkscape:label="Layer 1">
|
||||||
|
<rect
|
||||||
|
style="fill:#00ffcc;fill-opacity:1;stroke:none;stroke-width:0.39687499;stroke-linecap:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;paint-order:normal"
|
||||||
|
id="rect1235"
|
||||||
|
width="3.7041667"
|
||||||
|
height="3.7041805"
|
||||||
|
x="0.26458335"
|
||||||
|
y="293.03122" />
|
||||||
|
<path
|
||||||
|
style="fill:none;stroke:#808080;stroke-width:0.52916667;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:0.52916667, 0.52916666999999995;stroke-opacity:1;stroke-dashoffset:0"
|
||||||
|
d="m 0.26458333,292.76665 0,3.96875 H 4.2333333"
|
||||||
|
id="path1231"
|
||||||
|
inkscape:connector-curvature="0"
|
||||||
|
sodipodi:nodetypes="ccc" />
|
||||||
|
<path
|
||||||
|
style="fill:none;stroke:#000000;stroke-width:0.5291667;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
|
||||||
|
d="m 0,296.7354 c 2.0787582,0 3.96875,-2.11667 3.96875,-3.96875"
|
||||||
|
id="path1233"
|
||||||
|
inkscape:connector-curvature="0"
|
||||||
|
sodipodi:nodetypes="cc" />
|
||||||
|
<path
|
||||||
|
inkscape:connector-curvature="0"
|
||||||
|
id="path5323"
|
||||||
|
style="fill:#ff0000;fill-rule:evenodd;stroke:#df0000;stroke-width:0.26458332;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
|
||||||
|
d="m 2.8386428,295.34071 0.9362114,0.93622 m -0.9362104,-10e-6 0.9362094,-0.9362 m -1.1301062,0.4681 H 3.96875 m -0.6620015,0.662 v -1.324" />
|
||||||
|
</g>
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 3.2 KiB |
78
Editor/resources/IconNewGroup.svg
Normal file
@@ -0,0 +1,78 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||||
|
<!-- Created with Inkscape (http://www.inkscape.org/) -->
|
||||||
|
|
||||||
|
<svg
|
||||||
|
xmlns:dc="http://purl.org/dc/elements/1.1/"
|
||||||
|
xmlns:cc="http://creativecommons.org/ns#"
|
||||||
|
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
|
||||||
|
xmlns:svg="http://www.w3.org/2000/svg"
|
||||||
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
|
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||||
|
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||||
|
width="16"
|
||||||
|
height="16"
|
||||||
|
viewBox="0 0 4.2333332 4.2333335"
|
||||||
|
id="svg2"
|
||||||
|
version="1.1"
|
||||||
|
inkscape:version="0.91+devel+osxmenu r12922"
|
||||||
|
sodipodi:docname="NewSoundGroup.svg">
|
||||||
|
<defs
|
||||||
|
id="defs4" />
|
||||||
|
<sodipodi:namedview
|
||||||
|
id="base"
|
||||||
|
pagecolor="#393939"
|
||||||
|
bordercolor="#666666"
|
||||||
|
borderopacity="1.0"
|
||||||
|
inkscape:pageopacity="0"
|
||||||
|
inkscape:pageshadow="2"
|
||||||
|
inkscape:zoom="19.66"
|
||||||
|
inkscape:cx="6.046968"
|
||||||
|
inkscape:cy="6.9530957"
|
||||||
|
inkscape:document-units="px"
|
||||||
|
inkscape:current-layer="layer1"
|
||||||
|
showgrid="true"
|
||||||
|
units="px"
|
||||||
|
inkscape:window-width="1260"
|
||||||
|
inkscape:window-height="787"
|
||||||
|
inkscape:window-x="231"
|
||||||
|
inkscape:window-y="82"
|
||||||
|
inkscape:window-maximized="0"
|
||||||
|
showborder="true"
|
||||||
|
objecttolerance="4"
|
||||||
|
gridtolerance="4"
|
||||||
|
guidetolerance="5">
|
||||||
|
<inkscape:grid
|
||||||
|
type="xygrid"
|
||||||
|
id="grid4173"
|
||||||
|
empspacing="1"
|
||||||
|
visible="true" />
|
||||||
|
</sodipodi:namedview>
|
||||||
|
<metadata
|
||||||
|
id="metadata7">
|
||||||
|
<rdf:RDF>
|
||||||
|
<cc:Work
|
||||||
|
rdf:about="">
|
||||||
|
<dc:format>image/svg+xml</dc:format>
|
||||||
|
<dc:type
|
||||||
|
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
|
||||||
|
<dc:title></dc:title>
|
||||||
|
</cc:Work>
|
||||||
|
</rdf:RDF>
|
||||||
|
</metadata>
|
||||||
|
<g
|
||||||
|
inkscape:label="Layer 1"
|
||||||
|
inkscape:groupmode="layer"
|
||||||
|
id="layer1"
|
||||||
|
transform="translate(0,-292.76665)">
|
||||||
|
<path
|
||||||
|
style="opacity:1;fill:#fbd365;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1.67643285;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
|
||||||
|
d="m 1.3229167,293.04538 c 0.2645833,0 0.5291666,0.25044 0.5291666,0.51502 l 0,0.26458 1.8488138,0.0102 c 0.3165926,0.002 0.5239173,0.20975 0.5245413,0.52471 l 0.00313,1.57936 c 6.239e-4,0.31495 -0.2079439,0.53411 -0.5245413,0.53411 l -3.17666623,0 C 0.21076252,296.47339 0,296.2566 0,295.94165 c 4.054e-5,-0.82258 0,-2.38125 0,-2.38125 0,-0.26458 0.26458333,-0.51612 0.52916667,-0.51612 z"
|
||||||
|
id="rect4141"
|
||||||
|
inkscape:connector-curvature="0"
|
||||||
|
sodipodi:nodetypes="cccssssscccc" />
|
||||||
|
<path
|
||||||
|
id="path5876"
|
||||||
|
style="fill:#ff0000;fill-rule:evenodd;stroke:#df0000;stroke-width:0.26458332;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
|
||||||
|
d="m 2.8386428,295.07809 0.9362114,0.93622 m -0.9362104,-1e-5 0.9362094,-0.9362 m -1.1301062,0.4681 1.324003,0 m -0.6620015,0.662 0,-1.324" />
|
||||||
|
</g>
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 2.9 KiB |
100
Editor/resources/IconNewKeymap.svg
Normal file
@@ -0,0 +1,100 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||||
|
<!-- Created with Inkscape (http://www.inkscape.org/) -->
|
||||||
|
|
||||||
|
<svg
|
||||||
|
xmlns:dc="http://purl.org/dc/elements/1.1/"
|
||||||
|
xmlns:cc="http://creativecommons.org/ns#"
|
||||||
|
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
|
||||||
|
xmlns:svg="http://www.w3.org/2000/svg"
|
||||||
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
|
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||||
|
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||||
|
width="16"
|
||||||
|
height="16"
|
||||||
|
viewBox="0 0 4.2333332 4.2333335"
|
||||||
|
id="svg2"
|
||||||
|
version="1.1"
|
||||||
|
inkscape:version="0.91+devel+osxmenu r12922"
|
||||||
|
sodipodi:docname="NewKeymap.svg">
|
||||||
|
<defs
|
||||||
|
id="defs4" />
|
||||||
|
<sodipodi:namedview
|
||||||
|
id="base"
|
||||||
|
pagecolor="#393939"
|
||||||
|
bordercolor="#666666"
|
||||||
|
borderopacity="1.0"
|
||||||
|
inkscape:pageopacity="0"
|
||||||
|
inkscape:pageshadow="2"
|
||||||
|
inkscape:zoom="6.052834"
|
||||||
|
inkscape:cx="36.266061"
|
||||||
|
inkscape:cy="7.1823475"
|
||||||
|
inkscape:document-units="px"
|
||||||
|
inkscape:current-layer="layer1"
|
||||||
|
showgrid="true"
|
||||||
|
units="px"
|
||||||
|
inkscape:window-width="1260"
|
||||||
|
inkscape:window-height="787"
|
||||||
|
inkscape:window-x="0"
|
||||||
|
inkscape:window-y="23"
|
||||||
|
inkscape:window-maximized="0"
|
||||||
|
showborder="false"
|
||||||
|
objecttolerance="4"
|
||||||
|
gridtolerance="4"
|
||||||
|
guidetolerance="5">
|
||||||
|
<inkscape:grid
|
||||||
|
type="xygrid"
|
||||||
|
id="grid4173"
|
||||||
|
empspacing="1"
|
||||||
|
visible="false" />
|
||||||
|
</sodipodi:namedview>
|
||||||
|
<metadata
|
||||||
|
id="metadata7">
|
||||||
|
<rdf:RDF>
|
||||||
|
<cc:Work
|
||||||
|
rdf:about="">
|
||||||
|
<dc:format>image/svg+xml</dc:format>
|
||||||
|
<dc:type
|
||||||
|
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
|
||||||
|
<dc:title></dc:title>
|
||||||
|
</cc:Work>
|
||||||
|
</rdf:RDF>
|
||||||
|
</metadata>
|
||||||
|
<g
|
||||||
|
inkscape:label="Layer 1"
|
||||||
|
inkscape:groupmode="layer"
|
||||||
|
id="layer1"
|
||||||
|
transform="translate(0,-292.76665)">
|
||||||
|
<rect
|
||||||
|
style="opacity:1;fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:0.26458332;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
|
||||||
|
id="rect6472"
|
||||||
|
width="4.2333331"
|
||||||
|
height="3.1750097"
|
||||||
|
x="0"
|
||||||
|
y="293.29581" />
|
||||||
|
<path
|
||||||
|
style="fill:#ffffff;fill-rule:evenodd;stroke:none;stroke-width:0.26458332px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;fill-opacity:1"
|
||||||
|
d="m 0.26458333,293.5604 0,2.64583 0.79374997,0 0,-1.32291 -0.26458331,0 0,-1.32292 -0.52916666,0"
|
||||||
|
id="path6474"
|
||||||
|
inkscape:connector-curvature="0" />
|
||||||
|
<path
|
||||||
|
style="fill:#ffffff;fill-rule:evenodd;stroke:none;stroke-width:0.26458332px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;fill-opacity:1"
|
||||||
|
d="m 1.3229166,294.88332 0,1.32291 0.79375,0 0,-1.32291 -0.2645833,0 0,-1.32292 -0.2645833,0 0,1.32292 z"
|
||||||
|
id="path6476"
|
||||||
|
inkscape:connector-curvature="0" />
|
||||||
|
<path
|
||||||
|
style="fill:#ffffff;fill-rule:evenodd;stroke:none;stroke-width:0.26458332px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;fill-opacity:1"
|
||||||
|
d="m 2.38125,294.88332 0,1.32291 0.79375,0 0,-1.32291 0,-1.32292 -0.5291667,0 0,1.32292 z"
|
||||||
|
id="path6478"
|
||||||
|
inkscape:connector-curvature="0" />
|
||||||
|
<path
|
||||||
|
style="fill:#ffffff;fill-rule:evenodd;stroke:none;stroke-width:0.26458332px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;fill-opacity:1"
|
||||||
|
d="m 3.4395833,293.5604 0,2.64583 0.5291667,0 0,-2.64583 z"
|
||||||
|
id="path6480"
|
||||||
|
inkscape:connector-curvature="0" />
|
||||||
|
<path
|
||||||
|
id="path5323"
|
||||||
|
style="fill:#ff0000;fill-rule:evenodd;stroke:#df0000;stroke-width:0.26458332;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
|
||||||
|
d="m 2.8386428,295.07721 0.9362114,0.93622 m -0.9362104,-1e-5 0.9362094,-0.9362 m -1.1301062,0.4681 1.324003,0 m -0.6620015,0.662 0,-1.324"
|
||||||
|
inkscape:connector-curvature="0" />
|
||||||
|
</g>
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 3.8 KiB |
88
Editor/resources/IconNewLayers.svg
Normal file
@@ -0,0 +1,88 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||||
|
<!-- Created with Inkscape (http://www.inkscape.org/) -->
|
||||||
|
|
||||||
|
<svg
|
||||||
|
xmlns:dc="http://purl.org/dc/elements/1.1/"
|
||||||
|
xmlns:cc="http://creativecommons.org/ns#"
|
||||||
|
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
|
||||||
|
xmlns:svg="http://www.w3.org/2000/svg"
|
||||||
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
|
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||||
|
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||||
|
width="16"
|
||||||
|
height="16"
|
||||||
|
viewBox="0 0 4.2333332 4.2333335"
|
||||||
|
id="svg2"
|
||||||
|
version="1.1"
|
||||||
|
inkscape:version="0.91+devel+osxmenu r12922"
|
||||||
|
sodipodi:docname="NewLayers.svg">
|
||||||
|
<defs
|
||||||
|
id="defs4" />
|
||||||
|
<sodipodi:namedview
|
||||||
|
id="base"
|
||||||
|
pagecolor="#393939"
|
||||||
|
bordercolor="#666666"
|
||||||
|
borderopacity="1.0"
|
||||||
|
inkscape:pageopacity="0"
|
||||||
|
inkscape:pageshadow="2"
|
||||||
|
inkscape:zoom="2"
|
||||||
|
inkscape:cx="10.530468"
|
||||||
|
inkscape:cy="7.1823475"
|
||||||
|
inkscape:document-units="px"
|
||||||
|
inkscape:current-layer="layer1"
|
||||||
|
showgrid="true"
|
||||||
|
units="px"
|
||||||
|
inkscape:window-width="1260"
|
||||||
|
inkscape:window-height="787"
|
||||||
|
inkscape:window-x="131"
|
||||||
|
inkscape:window-y="170"
|
||||||
|
inkscape:window-maximized="0"
|
||||||
|
showborder="false"
|
||||||
|
objecttolerance="4"
|
||||||
|
gridtolerance="4"
|
||||||
|
guidetolerance="5">
|
||||||
|
<inkscape:grid
|
||||||
|
type="xygrid"
|
||||||
|
id="grid4173"
|
||||||
|
empspacing="1"
|
||||||
|
visible="false" />
|
||||||
|
</sodipodi:namedview>
|
||||||
|
<metadata
|
||||||
|
id="metadata7">
|
||||||
|
<rdf:RDF>
|
||||||
|
<cc:Work
|
||||||
|
rdf:about="">
|
||||||
|
<dc:format>image/svg+xml</dc:format>
|
||||||
|
<dc:type
|
||||||
|
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
|
||||||
|
<dc:title></dc:title>
|
||||||
|
</cc:Work>
|
||||||
|
</rdf:RDF>
|
||||||
|
</metadata>
|
||||||
|
<g
|
||||||
|
inkscape:label="Layer 1"
|
||||||
|
inkscape:groupmode="layer"
|
||||||
|
id="layer1"
|
||||||
|
transform="translate(0,-292.76665)">
|
||||||
|
<path
|
||||||
|
style="fill:#ff0066;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:0.26458332px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
|
||||||
|
d="m 0.26458333,293.29581 0,0.79375 3.70416667,0 0,-0.79375 z"
|
||||||
|
id="path7056"
|
||||||
|
inkscape:connector-curvature="0" />
|
||||||
|
<path
|
||||||
|
inkscape:connector-curvature="0"
|
||||||
|
id="path7058"
|
||||||
|
d="m 0.26458333,294.35415 0,0.79375 3.70416667,0 0,-0.79375 z"
|
||||||
|
style="fill:#ffcc00;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:0.26458332px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" />
|
||||||
|
<path
|
||||||
|
style="fill:#00aad4;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:0.26458332px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
|
||||||
|
d="m 0.26458333,295.41248 0,0.79375 3.70416667,0 0,-0.79375 z"
|
||||||
|
id="path7060"
|
||||||
|
inkscape:connector-curvature="0" />
|
||||||
|
<path
|
||||||
|
id="path5323"
|
||||||
|
style="fill:#ff0000;fill-rule:evenodd;stroke:#df0000;stroke-width:0.26458332;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
|
||||||
|
d="m 2.8386428,295.34072 0.9362114,0.93622 m -0.9362104,-1e-5 0.9362094,-0.9362 m -1.1301062,0.4681 1.324003,0 m -0.6620015,0.662 0,-1.324"
|
||||||
|
inkscape:connector-curvature="0" />
|
||||||
|
</g>
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 3.1 KiB |
83
Editor/resources/IconNewSongGroup.svg
Normal file
@@ -0,0 +1,83 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||||
|
<!-- Created with Inkscape (http://www.inkscape.org/) -->
|
||||||
|
|
||||||
|
<svg
|
||||||
|
xmlns:dc="http://purl.org/dc/elements/1.1/"
|
||||||
|
xmlns:cc="http://creativecommons.org/ns#"
|
||||||
|
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
|
||||||
|
xmlns:svg="http://www.w3.org/2000/svg"
|
||||||
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
|
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||||
|
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||||
|
width="16"
|
||||||
|
height="16"
|
||||||
|
viewBox="0 0 4.2333332 4.2333335"
|
||||||
|
id="svg2"
|
||||||
|
version="1.1"
|
||||||
|
inkscape:version="0.92.2 2405546, 2018-03-11"
|
||||||
|
sodipodi:docname="IconNewSongGroup.svg">
|
||||||
|
<defs
|
||||||
|
id="defs4" />
|
||||||
|
<sodipodi:namedview
|
||||||
|
id="base"
|
||||||
|
pagecolor="#393939"
|
||||||
|
bordercolor="#666666"
|
||||||
|
borderopacity="1.0"
|
||||||
|
inkscape:pageopacity="0"
|
||||||
|
inkscape:pageshadow="2"
|
||||||
|
inkscape:zoom="29.730996"
|
||||||
|
inkscape:cx="3.0052979"
|
||||||
|
inkscape:cy="9.0045012"
|
||||||
|
inkscape:document-units="px"
|
||||||
|
inkscape:current-layer="layer1"
|
||||||
|
showgrid="true"
|
||||||
|
units="px"
|
||||||
|
inkscape:window-width="1260"
|
||||||
|
inkscape:window-height="787"
|
||||||
|
inkscape:window-x="0"
|
||||||
|
inkscape:window-y="40"
|
||||||
|
inkscape:window-maximized="0"
|
||||||
|
showborder="false"
|
||||||
|
objecttolerance="4"
|
||||||
|
gridtolerance="4"
|
||||||
|
guidetolerance="5">
|
||||||
|
<inkscape:grid
|
||||||
|
type="xygrid"
|
||||||
|
id="grid4173"
|
||||||
|
empspacing="1"
|
||||||
|
visible="false" />
|
||||||
|
</sodipodi:namedview>
|
||||||
|
<metadata
|
||||||
|
id="metadata7">
|
||||||
|
<rdf:RDF>
|
||||||
|
<cc:Work
|
||||||
|
rdf:about="">
|
||||||
|
<dc:format>image/svg+xml</dc:format>
|
||||||
|
<dc:type
|
||||||
|
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
|
||||||
|
<dc:title />
|
||||||
|
</cc:Work>
|
||||||
|
</rdf:RDF>
|
||||||
|
</metadata>
|
||||||
|
<g
|
||||||
|
inkscape:label="Layer 1"
|
||||||
|
inkscape:groupmode="layer"
|
||||||
|
id="layer1"
|
||||||
|
transform="translate(0,-292.76665)">
|
||||||
|
<path
|
||||||
|
style="opacity:1;fill:#ff5599;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1.67643285;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
|
||||||
|
d="m 1.3229167,293.04538 c 0.2645833,0 0.5291666,0.25044 0.5291666,0.51502 l 0,0.26458 1.8488138,0.0102 c 0.3165926,0.002 0.5239173,0.20975 0.5245413,0.52471 l 0.00313,1.57936 c 6.239e-4,0.31495 -0.2079439,0.53411 -0.5245413,0.53411 l -3.17666623,0 C 0.21076252,296.47339 0,296.2566 0,295.94165 c 4.054e-5,-0.82258 0,-2.38125 0,-2.38125 0,-0.26458 0.26458333,-0.51612 0.52916667,-0.51612 z"
|
||||||
|
id="rect4141"
|
||||||
|
inkscape:connector-curvature="0"
|
||||||
|
sodipodi:nodetypes="cccssssscccc" />
|
||||||
|
<path
|
||||||
|
inkscape:connector-curvature="0"
|
||||||
|
id="path868"
|
||||||
|
style="fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.26458332;stroke-miterlimit:4;stroke-dasharray:none"
|
||||||
|
d="m 1.8675862,295.87272 a 0.57456181,0.36088177 0 0 1 -0.5745618,0.36089 0.57456181,0.36088177 0 0 1 -0.57456172,-0.36089 0.57456181,0.36088177 0 0 1 0.57456172,-0.36088 0.57456181,0.36088177 0 0 1 0.5745618,0.36088 z m 1.3298265,-0.001 a 0.57456181,0.36088177 0 0 1 -0.5745619,0.36089 0.57456181,0.36088177 0 0 1 -0.5745618,-0.36089 0.57456181,0.36088177 0 0 1 0.5745618,-0.36088 0.57456181,0.36088177 0 0 1 0.5745619,0.36088 z m -0.253445,-1.78193 0.253445,0.006 v 1.77617 c -0.2177221,0.0701 -0.286996,-0.0173 -0.3755473,-0.1676 l 0.00387,-0.79478 H 1.868454 v 0.95424 c -0.2323614,-0.008 -0.2369279,-0.14254 -0.3755412,-0.22458 v -1.54879 z" />
|
||||||
|
<path
|
||||||
|
id="path5323"
|
||||||
|
style="fill:#ff0000;fill-rule:evenodd;stroke:#df0000;stroke-width:0.26458332;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
|
||||||
|
d="m 2.8386428,295.07809 0.9362114,0.93622 m -0.9362104,-1e-5 0.9362094,-0.9362 m -1.1301062,0.4681 1.324003,0 m -0.6620015,0.662 0,-1.324" />
|
||||||
|
</g>
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 3.7 KiB |
84
Editor/resources/IconNewSoundGroup.svg
Normal file
@@ -0,0 +1,84 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||||
|
<!-- Created with Inkscape (http://www.inkscape.org/) -->
|
||||||
|
|
||||||
|
<svg
|
||||||
|
xmlns:dc="http://purl.org/dc/elements/1.1/"
|
||||||
|
xmlns:cc="http://creativecommons.org/ns#"
|
||||||
|
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
|
||||||
|
xmlns:svg="http://www.w3.org/2000/svg"
|
||||||
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
|
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||||
|
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||||
|
width="16"
|
||||||
|
height="16"
|
||||||
|
viewBox="0 0 4.2333332 4.2333335"
|
||||||
|
id="svg2"
|
||||||
|
version="1.1"
|
||||||
|
inkscape:version="0.92.2 2405546, 2018-03-11"
|
||||||
|
sodipodi:docname="IconNewSoundGroup.svg">
|
||||||
|
<defs
|
||||||
|
id="defs4" />
|
||||||
|
<sodipodi:namedview
|
||||||
|
id="base"
|
||||||
|
pagecolor="#393939"
|
||||||
|
bordercolor="#666666"
|
||||||
|
borderopacity="1.0"
|
||||||
|
inkscape:pageopacity="0"
|
||||||
|
inkscape:pageshadow="2"
|
||||||
|
inkscape:zoom="31.94"
|
||||||
|
inkscape:cx="9.7896878"
|
||||||
|
inkscape:cy="6.9530957"
|
||||||
|
inkscape:document-units="px"
|
||||||
|
inkscape:current-layer="layer1"
|
||||||
|
showgrid="true"
|
||||||
|
units="px"
|
||||||
|
inkscape:window-width="1260"
|
||||||
|
inkscape:window-height="777"
|
||||||
|
inkscape:window-x="2038"
|
||||||
|
inkscape:window-y="1136"
|
||||||
|
inkscape:window-maximized="0"
|
||||||
|
showborder="true"
|
||||||
|
objecttolerance="4"
|
||||||
|
gridtolerance="4"
|
||||||
|
guidetolerance="5">
|
||||||
|
<inkscape:grid
|
||||||
|
type="xygrid"
|
||||||
|
id="grid4173"
|
||||||
|
empspacing="1"
|
||||||
|
visible="true" />
|
||||||
|
</sodipodi:namedview>
|
||||||
|
<metadata
|
||||||
|
id="metadata7">
|
||||||
|
<rdf:RDF>
|
||||||
|
<cc:Work
|
||||||
|
rdf:about="">
|
||||||
|
<dc:format>image/svg+xml</dc:format>
|
||||||
|
<dc:type
|
||||||
|
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
|
||||||
|
<dc:title />
|
||||||
|
</cc:Work>
|
||||||
|
</rdf:RDF>
|
||||||
|
</metadata>
|
||||||
|
<g
|
||||||
|
inkscape:label="Layer 1"
|
||||||
|
inkscape:groupmode="layer"
|
||||||
|
id="layer1"
|
||||||
|
transform="translate(0,-292.76665)">
|
||||||
|
<path
|
||||||
|
style="opacity:1;fill:#04e2ff;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1.67643285;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
|
||||||
|
d="m 1.3229167,293.04538 c 0.2645833,0 0.5291666,0.25044 0.5291666,0.51502 l 0,0.26458 1.8488138,0.0102 c 0.3165926,0.002 0.5239173,0.20975 0.5245413,0.52471 l 0.00313,1.57936 c 6.239e-4,0.31495 -0.2079439,0.53411 -0.5245413,0.53411 l -3.17666623,0 C 0.21076252,296.47339 0,296.2566 0,295.94165 c 4.054e-5,-0.82258 0,-2.38125 0,-2.38125 0,-0.26458 0.26458333,-0.51612 0.52916667,-0.51612 z"
|
||||||
|
id="rect4141"
|
||||||
|
inkscape:connector-curvature="0"
|
||||||
|
sodipodi:nodetypes="cccssssscccc" />
|
||||||
|
<path
|
||||||
|
id="path1184"
|
||||||
|
title="sin(x*4*pi)*sin(x*pi)"
|
||||||
|
d="m 0.52916699,295.1479 c 0.11759258,-1.5e-4 0.23518516,-0.18652 0.35277774,-0.31191 0.11759258,-0.1254 0.23518517,-0.1236 0.35277777,0.10832 0.1175926,0.23193 0.2351851,0.66463 0.3527777,0.89812 0.1175926,0.23349 0.2351852,0.20457 0.3527778,-0.10832 0.1175925,-0.3129 0.2351851,-0.85907 0.3527777,-1.17242 0.1175926,-0.31334 0.2351852,-0.3414 0.3527777,-0.10832 0.1175926,0.23308 0.2351852,0.66584 0.3527778,0.89812 0.1175926,0.23228 0.2351851,0.23355 0.3527778,0.10832 0.1175925,-0.12522 0.235185,-0.31176 0.3527777,-0.31191"
|
||||||
|
style="fill:none;fill-opacity:1;stroke:#000000;stroke-width:0.396875;stroke-linecap:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;paint-order:normal"
|
||||||
|
inkscape:connector-curvature="0" />
|
||||||
|
<path
|
||||||
|
id="path5876"
|
||||||
|
style="fill:#ff0000;fill-rule:evenodd;stroke:#df0000;stroke-width:0.26458332;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
|
||||||
|
d="m 2.8386428,295.07809 0.9362114,0.93622 m -0.9362104,-1e-5 0.9362094,-0.9362 m -1.1301062,0.4681 1.324003,0 m -0.6620015,0.662 0,-1.324" />
|
||||||
|
</g>
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 3.7 KiB |
79
Editor/resources/IconNewSoundMacro.svg
Normal file
@@ -0,0 +1,79 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||||
|
<!-- Created with Inkscape (http://www.inkscape.org/) -->
|
||||||
|
|
||||||
|
<svg
|
||||||
|
xmlns:dc="http://purl.org/dc/elements/1.1/"
|
||||||
|
xmlns:cc="http://creativecommons.org/ns#"
|
||||||
|
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
|
||||||
|
xmlns:svg="http://www.w3.org/2000/svg"
|
||||||
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
|
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||||
|
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||||
|
width="16"
|
||||||
|
height="16"
|
||||||
|
viewBox="0 0 4.2333332 4.2333335"
|
||||||
|
id="svg2"
|
||||||
|
version="1.1"
|
||||||
|
inkscape:version="0.92.2 2405546, 2018-03-11"
|
||||||
|
sodipodi:docname="IconNewSoundMacro.svg">
|
||||||
|
<defs
|
||||||
|
id="defs4" />
|
||||||
|
<sodipodi:namedview
|
||||||
|
id="base"
|
||||||
|
pagecolor="#393939"
|
||||||
|
bordercolor="#666666"
|
||||||
|
borderopacity="1.0"
|
||||||
|
inkscape:pageopacity="0"
|
||||||
|
inkscape:pageshadow="2"
|
||||||
|
inkscape:zoom="30.33"
|
||||||
|
inkscape:cx="2.9941402"
|
||||||
|
inkscape:cy="4.6784097"
|
||||||
|
inkscape:document-units="px"
|
||||||
|
inkscape:current-layer="layer1"
|
||||||
|
showgrid="true"
|
||||||
|
units="px"
|
||||||
|
inkscape:window-width="1260"
|
||||||
|
inkscape:window-height="787"
|
||||||
|
inkscape:window-x="606"
|
||||||
|
inkscape:window-y="435"
|
||||||
|
inkscape:window-maximized="0"
|
||||||
|
showborder="false"
|
||||||
|
objecttolerance="4"
|
||||||
|
gridtolerance="4"
|
||||||
|
guidetolerance="5">
|
||||||
|
<inkscape:grid
|
||||||
|
type="xygrid"
|
||||||
|
id="grid4173"
|
||||||
|
empspacing="1"
|
||||||
|
visible="true" />
|
||||||
|
</sodipodi:namedview>
|
||||||
|
<metadata
|
||||||
|
id="metadata7">
|
||||||
|
<rdf:RDF>
|
||||||
|
<cc:Work
|
||||||
|
rdf:about="">
|
||||||
|
<dc:format>image/svg+xml</dc:format>
|
||||||
|
<dc:type
|
||||||
|
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
|
||||||
|
<dc:title></dc:title>
|
||||||
|
</cc:Work>
|
||||||
|
</rdf:RDF>
|
||||||
|
</metadata>
|
||||||
|
<g
|
||||||
|
inkscape:label="Layer 1"
|
||||||
|
inkscape:groupmode="layer"
|
||||||
|
id="layer1"
|
||||||
|
transform="translate(0,-292.76665)">
|
||||||
|
<path
|
||||||
|
style="opacity:1;fill:#62ff04;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:0.30031049;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
|
||||||
|
d="m 0.96793039,292.83382 2.60268711,1.68348 c 0.392506,0.24382 0.3952841,0.49652 0,0.73535 l -2.60268711,1.69163 c -0.2789936,0.18133 -0.6006367,-0.0548 -0.6006367,-0.39294 v -3.35322 c 0,-0.33276 0.3212394,-0.54502 0.6006367,-0.3643 z"
|
||||||
|
id="rect5899-3"
|
||||||
|
inkscape:connector-curvature="0"
|
||||||
|
sodipodi:nodetypes="sccssss" />
|
||||||
|
<path
|
||||||
|
id="path5323"
|
||||||
|
style="fill:#ff0000;fill-rule:evenodd;stroke:#df0000;stroke-width:0.26458332;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
|
||||||
|
d="m 2.8386428,295.6133 0.9362114,0.93622 m -0.9362104,-10e-6 0.9362094,-0.9362 m -1.1301062,0.4681 H 3.96875 m -0.6620015,0.662 v -1.324"
|
||||||
|
inkscape:connector-curvature="0" />
|
||||||
|
</g>
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 2.8 KiB |
92
Editor/resources/IconOpen.svg
Normal file
@@ -0,0 +1,92 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||||
|
<!-- Created with Inkscape (http://www.inkscape.org/) -->
|
||||||
|
|
||||||
|
<svg
|
||||||
|
xmlns:dc="http://purl.org/dc/elements/1.1/"
|
||||||
|
xmlns:cc="http://creativecommons.org/ns#"
|
||||||
|
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
|
||||||
|
xmlns:svg="http://www.w3.org/2000/svg"
|
||||||
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
|
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||||
|
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||||
|
width="16"
|
||||||
|
height="16"
|
||||||
|
viewBox="0 0 4.2333332 4.2333335"
|
||||||
|
id="svg2"
|
||||||
|
version="1.1"
|
||||||
|
inkscape:version="0.91+devel+osxmenu r12922"
|
||||||
|
sodipodi:docname="IconOpen.svg">
|
||||||
|
<defs
|
||||||
|
id="defs4" />
|
||||||
|
<sodipodi:namedview
|
||||||
|
id="base"
|
||||||
|
pagecolor="#393939"
|
||||||
|
bordercolor="#666666"
|
||||||
|
borderopacity="1.0"
|
||||||
|
inkscape:pageopacity="0"
|
||||||
|
inkscape:pageshadow="2"
|
||||||
|
inkscape:zoom="2"
|
||||||
|
inkscape:cx="8.3840992"
|
||||||
|
inkscape:cy="8.1216613"
|
||||||
|
inkscape:document-units="px"
|
||||||
|
inkscape:current-layer="layer1"
|
||||||
|
showgrid="true"
|
||||||
|
units="px"
|
||||||
|
inkscape:window-width="1260"
|
||||||
|
inkscape:window-height="787"
|
||||||
|
inkscape:window-x="231"
|
||||||
|
inkscape:window-y="60"
|
||||||
|
inkscape:window-maximized="0"
|
||||||
|
showborder="false"
|
||||||
|
objecttolerance="4"
|
||||||
|
gridtolerance="4"
|
||||||
|
guidetolerance="5">
|
||||||
|
<inkscape:grid
|
||||||
|
type="xygrid"
|
||||||
|
id="grid4173"
|
||||||
|
empspacing="1"
|
||||||
|
visible="false" />
|
||||||
|
</sodipodi:namedview>
|
||||||
|
<metadata
|
||||||
|
id="metadata7">
|
||||||
|
<rdf:RDF>
|
||||||
|
<cc:Work
|
||||||
|
rdf:about="">
|
||||||
|
<dc:format>image/svg+xml</dc:format>
|
||||||
|
<dc:type
|
||||||
|
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
|
||||||
|
<dc:title></dc:title>
|
||||||
|
</cc:Work>
|
||||||
|
</rdf:RDF>
|
||||||
|
</metadata>
|
||||||
|
<g
|
||||||
|
inkscape:label="Layer 1"
|
||||||
|
inkscape:groupmode="layer"
|
||||||
|
id="layer1"
|
||||||
|
transform="translate(0,-292.76665)">
|
||||||
|
<path
|
||||||
|
style="opacity:1;fill:#fbd365;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1.67643285;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
|
||||||
|
d="m 1.3229167,293.04538 c 0.2645833,0 0.5291666,0.25044 0.5291666,0.51502 l 0,0.26458 1.8488138,0.0102 c 0.3165926,0.002 0.5239173,0.20975 0.5245413,0.52471 l 0.00313,1.57936 c 6.239e-4,0.31495 -0.2079439,0.53411 -0.5245413,0.53411 l -3.17666623,0 C 0.21076252,296.47339 0,296.2566 0,295.94165 c 4.054e-5,-0.82258 0,-2.38125 0,-2.38125 0,-0.26458 0.26458333,-0.51612 0.52916667,-0.51612 z"
|
||||||
|
id="rect4141"
|
||||||
|
inkscape:connector-curvature="0"
|
||||||
|
sodipodi:nodetypes="cccssssscccc" />
|
||||||
|
<path
|
||||||
|
style="fill:#00eaff;fill-rule:evenodd;stroke:#2a2a2a;stroke-width:0.26458332;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;fill-opacity:1"
|
||||||
|
d="m 1.1851666,295.02021 1.8652063,-0.005 c 0,0.50687 -0.4045396,1.05375 -0.9337062,1.05512 -0.5291667,0 -0.9315001,-0.53641 -0.9315001,-1.04967 z"
|
||||||
|
id="path4753"
|
||||||
|
inkscape:connector-curvature="0"
|
||||||
|
sodipodi:nodetypes="cccc" />
|
||||||
|
<circle
|
||||||
|
style="opacity:1;fill:#2a2a2a;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:0.3379305;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
|
||||||
|
id="path4755"
|
||||||
|
cx="1.723109"
|
||||||
|
cy="294.216"
|
||||||
|
r="0.19592465" />
|
||||||
|
<circle
|
||||||
|
r="0.19592465"
|
||||||
|
cy="294.2269"
|
||||||
|
cx="2.4938412"
|
||||||
|
id="circle4757"
|
||||||
|
style="opacity:1;fill:#2a2a2a;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:0.3379305;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" />
|
||||||
|
</g>
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 3.6 KiB |
118
Editor/resources/IconPaintbrush.svg
Normal file
@@ -0,0 +1,118 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||||
|
<!-- Created with Inkscape (http://www.inkscape.org/) -->
|
||||||
|
|
||||||
|
<svg
|
||||||
|
xmlns:dc="http://purl.org/dc/elements/1.1/"
|
||||||
|
xmlns:cc="http://creativecommons.org/ns#"
|
||||||
|
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
|
||||||
|
xmlns:svg="http://www.w3.org/2000/svg"
|
||||||
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
|
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||||
|
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||||
|
width="32"
|
||||||
|
height="32"
|
||||||
|
viewBox="0 0 8.4666664 8.4666672"
|
||||||
|
version="1.1"
|
||||||
|
id="svg8"
|
||||||
|
inkscape:version="0.92.2 2405546, 2018-03-11"
|
||||||
|
sodipodi:docname="IconPaintbrush.svg">
|
||||||
|
<defs
|
||||||
|
id="defs2" />
|
||||||
|
<sodipodi:namedview
|
||||||
|
id="base"
|
||||||
|
pagecolor="#353535"
|
||||||
|
bordercolor="#666666"
|
||||||
|
borderopacity="1.0"
|
||||||
|
inkscape:pageopacity="0"
|
||||||
|
inkscape:pageshadow="2"
|
||||||
|
inkscape:zoom="119.2182"
|
||||||
|
inkscape:cx="10.254924"
|
||||||
|
inkscape:cy="16.654642"
|
||||||
|
inkscape:document-units="px"
|
||||||
|
inkscape:current-layer="layer1"
|
||||||
|
showgrid="true"
|
||||||
|
units="px"
|
||||||
|
inkscape:window-width="3840"
|
||||||
|
inkscape:window-height="2079"
|
||||||
|
inkscape:window-x="0"
|
||||||
|
inkscape:window-y="40"
|
||||||
|
inkscape:window-maximized="1"
|
||||||
|
gridtolerance="10"
|
||||||
|
showguides="false"
|
||||||
|
showborder="true">
|
||||||
|
<inkscape:grid
|
||||||
|
type="xygrid"
|
||||||
|
id="grid817"
|
||||||
|
empspacing="0"
|
||||||
|
spacingx="0.52916666"
|
||||||
|
spacingy="0.52916666"
|
||||||
|
visible="true" />
|
||||||
|
</sodipodi:namedview>
|
||||||
|
<metadata
|
||||||
|
id="metadata5">
|
||||||
|
<rdf:RDF>
|
||||||
|
<cc:Work
|
||||||
|
rdf:about="">
|
||||||
|
<dc:format>image/svg+xml</dc:format>
|
||||||
|
<dc:type
|
||||||
|
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
|
||||||
|
<dc:title />
|
||||||
|
</cc:Work>
|
||||||
|
</rdf:RDF>
|
||||||
|
</metadata>
|
||||||
|
<g
|
||||||
|
inkscape:label="Layer 1"
|
||||||
|
inkscape:groupmode="layer"
|
||||||
|
id="layer1"
|
||||||
|
transform="translate(0,-288.53332)">
|
||||||
|
<path
|
||||||
|
sodipodi:type="inkscape:offset"
|
||||||
|
inkscape:radius="0.24255499"
|
||||||
|
inkscape:original="M 7.9375 289.0625 C 7.6711732 288.79616 2.6464844 293.29492 2.6464844 293.29492 L 3.7050781 294.35352 C 3.7050781 294.35352 8.2038267 289.32882 7.9375 289.0625 z "
|
||||||
|
style="fill:none;fill-opacity:1;stroke:#000019;stroke-width:0.26458335;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
|
||||||
|
id="path5257"
|
||||||
|
d="m 7.8886719,288.80859 c -0.056389,0.002 -0.097096,0.0152 -0.1367188,0.0293 -0.079245,0.0282 -0.1534463,0.068 -0.2421875,0.12109 -0.1774822,0.10627 -0.4004054,0.26416 -0.6582031,0.45899 -0.5155954,0.38965 -1.1699607,0.92941 -1.8164063,1.47656 -1.2928911,1.0943 -2.5507812,2.21875 -2.5507812,2.21875 a 0.24257925,0.24257925 0 0 0 -0.00977,0.35352 l 1.0585937,1.05859 a 0.24257925,0.24257925 0 0 0 0.3535157,-0.01 c 0,0 1.1244523,-1.25788 2.21875,-2.55078 0.5471488,-0.64644 1.0869076,-1.30081 1.4765624,-1.8164 0.1948275,-0.2578 0.3527187,-0.48072 0.4589844,-0.65821 0.053133,-0.0887 0.092867,-0.16294 0.1210938,-0.24218 0.014113,-0.0396 0.027013,-0.0803 0.029297,-0.13672 0.00228,-0.0564 -0.00982,-0.1485 -0.082031,-0.22071 -0.072205,-0.0722 -0.1643139,-0.0843 -0.2207031,-0.082 z" />
|
||||||
|
<path
|
||||||
|
style="fill:#333333;fill-opacity:1;stroke:#ffffff;stroke-width:0.26458335;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
|
||||||
|
d="m 7.9375067,289.06249 c 0.2663267,0.26632 -4.2333372,5.29165 -4.2333372,5.29165 l -1.0583343,-1.05832 c 0,0 5.0253447,-4.49967 5.2916715,-4.23333 z"
|
||||||
|
id="path846"
|
||||||
|
inkscape:connector-curvature="0"
|
||||||
|
sodipodi:nodetypes="zccz" />
|
||||||
|
<path
|
||||||
|
style="fill:#333333;fill-opacity:1;stroke:#ffffff;stroke-width:0.26458335;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
|
||||||
|
d="m 3.7041695,294.35414 c 0.7934571,0.79347 -2.1166685,2.11668 -3.17500284,2.11668 0,-1.05833 1.32960554,-3.96208 2.11666854,-3.175 z"
|
||||||
|
id="path848"
|
||||||
|
inkscape:connector-curvature="0"
|
||||||
|
sodipodi:nodetypes="cccc" />
|
||||||
|
<path
|
||||||
|
style="fill:none;stroke:#ffffff;stroke-width:0.26458335;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
|
||||||
|
d="m 2.7321623,293.41165 c 0,0 -1.1446613,0.94249 -2.20299564,3.05917"
|
||||||
|
id="path850"
|
||||||
|
inkscape:connector-curvature="0"
|
||||||
|
sodipodi:nodetypes="cc" />
|
||||||
|
<path
|
||||||
|
style="fill:none;stroke:#ffffff;stroke-width:0.26458335;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
|
||||||
|
d="m 3.6041925,294.27028 c 0,0 -0.9583573,1.14221 -3.07502584,2.20054"
|
||||||
|
id="path852"
|
||||||
|
inkscape:connector-curvature="0"
|
||||||
|
sodipodi:nodetypes="cc" />
|
||||||
|
<path
|
||||||
|
style="fill:none;stroke:#ffffff;stroke-width:0.26458335;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
|
||||||
|
d="m 3.1750023,293.82499 -2.64583564,2.64583"
|
||||||
|
id="path854"
|
||||||
|
inkscape:connector-curvature="0" />
|
||||||
|
<path
|
||||||
|
sodipodi:type="inkscape:offset"
|
||||||
|
inkscape:radius="0.25359377"
|
||||||
|
inkscape:original="M 2.6464844 293.29492 C 1.8594214 292.50784 0.52929688 295.41237 0.52929688 296.4707 C 1.5876312 296.4707 4.4985352 295.14699 3.7050781 294.35352 L 2.6464844 293.29492 z "
|
||||||
|
style="fill:none;fill-opacity:1;stroke:#00001b;stroke-width:0.26458335;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
|
||||||
|
id="path5261"
|
||||||
|
d="m 2.3164062,292.9082 c -0.181907,0.01 -0.3430295,0.0908 -0.4863281,0.19922 -0.2865971,0.21692 -0.5328425,0.56219 -0.7578125,0.95899 -0.44993989,0.79359 -0.79687498,1.76889 -0.79687498,2.40429 a 0.25361913,0.25361913 0 0 0 0.25390626,0.25391 c 0.63489452,0 1.61169302,-0.34575 2.40625002,-0.79492 0.3972785,-0.22459 0.7421604,-0.47049 0.9589843,-0.75781 0.108412,-0.14367 0.1899049,-0.30393 0.1992188,-0.48633 0.00931,-0.1824 -0.069928,-0.37266 -0.2089844,-0.51172 l -1.0585937,-1.0586 C 2.6875905,292.97665 2.4983133,292.89817 2.3164062,292.9082 Z" />
|
||||||
|
<path
|
||||||
|
style="fill:#fffffd;fill-opacity:1;stroke:none;stroke-width:0.26458356px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
|
||||||
|
d="m 3.3534735,292.49828 1.1682763,1.12584 -0.6609111,0.75797 -1.2383055,-1.2582 z"
|
||||||
|
id="path1960"
|
||||||
|
inkscape:connector-curvature="0"
|
||||||
|
sodipodi:nodetypes="ccccc" />
|
||||||
|
</g>
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 6.3 KiB |
75
Editor/resources/IconRemove.svg
Normal file
@@ -0,0 +1,75 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||||
|
<!-- Created with Inkscape (http://www.inkscape.org/) -->
|
||||||
|
|
||||||
|
<svg
|
||||||
|
xmlns:dc="http://purl.org/dc/elements/1.1/"
|
||||||
|
xmlns:cc="http://creativecommons.org/ns#"
|
||||||
|
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
|
||||||
|
xmlns:svg="http://www.w3.org/2000/svg"
|
||||||
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
|
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||||
|
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||||
|
width="24"
|
||||||
|
height="24"
|
||||||
|
viewBox="0 0 6.3499998 6.3500004"
|
||||||
|
version="1.1"
|
||||||
|
id="svg8"
|
||||||
|
inkscape:version="0.92.2 2405546, 2018-03-11"
|
||||||
|
sodipodi:docname="IconRemove.svg">
|
||||||
|
<defs
|
||||||
|
id="defs2" />
|
||||||
|
<sodipodi:namedview
|
||||||
|
id="base"
|
||||||
|
pagecolor="#353535"
|
||||||
|
bordercolor="#666666"
|
||||||
|
borderopacity="1.0"
|
||||||
|
inkscape:pageopacity="0"
|
||||||
|
inkscape:pageshadow="2"
|
||||||
|
inkscape:zoom="39.327341"
|
||||||
|
inkscape:cx="14.81887"
|
||||||
|
inkscape:cy="14.927514"
|
||||||
|
inkscape:document-units="px"
|
||||||
|
inkscape:current-layer="layer1"
|
||||||
|
showgrid="true"
|
||||||
|
units="px"
|
||||||
|
inkscape:window-width="3840"
|
||||||
|
inkscape:window-height="2079"
|
||||||
|
inkscape:window-x="0"
|
||||||
|
inkscape:window-y="40"
|
||||||
|
inkscape:window-maximized="1"
|
||||||
|
gridtolerance="4"
|
||||||
|
showguides="false"
|
||||||
|
showborder="true"
|
||||||
|
objecttolerance="13">
|
||||||
|
<inkscape:grid
|
||||||
|
type="xygrid"
|
||||||
|
id="grid817"
|
||||||
|
empspacing="0"
|
||||||
|
spacingx="0.52916666"
|
||||||
|
spacingy="0.52916666"
|
||||||
|
visible="true" />
|
||||||
|
</sodipodi:namedview>
|
||||||
|
<metadata
|
||||||
|
id="metadata5">
|
||||||
|
<rdf:RDF>
|
||||||
|
<cc:Work
|
||||||
|
rdf:about="">
|
||||||
|
<dc:format>image/svg+xml</dc:format>
|
||||||
|
<dc:type
|
||||||
|
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
|
||||||
|
<dc:title></dc:title>
|
||||||
|
</cc:Work>
|
||||||
|
</rdf:RDF>
|
||||||
|
</metadata>
|
||||||
|
<g
|
||||||
|
inkscape:label="Layer 1"
|
||||||
|
inkscape:groupmode="layer"
|
||||||
|
id="layer1"
|
||||||
|
transform="translate(0,-290.64999)">
|
||||||
|
<path
|
||||||
|
style="fill:#ff0000;stroke:none;stroke-width:0.26458335px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
|
||||||
|
d="m 0,292.76666 v 2.11666 h 6.3499999 v -2.11666 z"
|
||||||
|
id="path867"
|
||||||
|
inkscape:connector-curvature="0" />
|
||||||
|
</g>
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 2.1 KiB |
74
Editor/resources/IconSample.svg
Normal file
@@ -0,0 +1,74 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||||
|
<!-- Created with Inkscape (http://www.inkscape.org/) -->
|
||||||
|
|
||||||
|
<svg
|
||||||
|
xmlns:dc="http://purl.org/dc/elements/1.1/"
|
||||||
|
xmlns:cc="http://creativecommons.org/ns#"
|
||||||
|
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
|
||||||
|
xmlns:svg="http://www.w3.org/2000/svg"
|
||||||
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
|
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||||
|
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||||
|
width="16"
|
||||||
|
height="16"
|
||||||
|
viewBox="0 0 4.2333332 4.2333335"
|
||||||
|
id="svg2"
|
||||||
|
version="1.1"
|
||||||
|
inkscape:version="0.92.2 2405546, 2018-03-11"
|
||||||
|
sodipodi:docname="IconSample.svg">
|
||||||
|
<sodipodi:namedview
|
||||||
|
id="base"
|
||||||
|
pagecolor="#393939"
|
||||||
|
bordercolor="#666666"
|
||||||
|
borderopacity="1.0"
|
||||||
|
inkscape:pageopacity="0"
|
||||||
|
inkscape:pageshadow="2"
|
||||||
|
inkscape:zoom="34.25"
|
||||||
|
inkscape:cx="8.0516224"
|
||||||
|
inkscape:cy="8.452632"
|
||||||
|
inkscape:document-units="px"
|
||||||
|
inkscape:current-layer="layer1"
|
||||||
|
showgrid="true"
|
||||||
|
units="px"
|
||||||
|
inkscape:window-width="3840"
|
||||||
|
inkscape:window-height="2079"
|
||||||
|
inkscape:window-x="0"
|
||||||
|
inkscape:window-y="40"
|
||||||
|
inkscape:window-maximized="1"
|
||||||
|
showborder="true"
|
||||||
|
objecttolerance="4"
|
||||||
|
gridtolerance="4"
|
||||||
|
guidetolerance="5">
|
||||||
|
<inkscape:grid
|
||||||
|
visible="true"
|
||||||
|
empspacing="1"
|
||||||
|
id="grid4173"
|
||||||
|
type="xygrid" />
|
||||||
|
</sodipodi:namedview>
|
||||||
|
<defs
|
||||||
|
id="defs4" />
|
||||||
|
<metadata
|
||||||
|
id="metadata7">
|
||||||
|
<rdf:RDF>
|
||||||
|
<cc:Work
|
||||||
|
rdf:about="">
|
||||||
|
<dc:format>image/svg+xml</dc:format>
|
||||||
|
<dc:type
|
||||||
|
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
|
||||||
|
<dc:title></dc:title>
|
||||||
|
</cc:Work>
|
||||||
|
</rdf:RDF>
|
||||||
|
</metadata>
|
||||||
|
<g
|
||||||
|
transform="translate(0,-292.76665)"
|
||||||
|
id="layer1"
|
||||||
|
inkscape:groupmode="layer"
|
||||||
|
inkscape:label="Layer 1">
|
||||||
|
<path
|
||||||
|
id="path1184"
|
||||||
|
title="sin(x*4*pi)*sin(x*pi)"
|
||||||
|
d="m 0.36489826,294.88332 c 0.12976062,-1.7e-4 0.25952124,-0.20582 0.38928188,-0.34418 0.12976062,-0.13838 0.25952116,-0.13639 0.38928186,0.11952 0.1297606,0.25593 0.2595211,0.73341 0.3892818,0.99106 0.1297606,0.25765 0.2595213,0.22574 0.3892819,-0.11953 0.1297606,-0.34528 0.2595212,-0.94796 0.3892819,-1.29374 0.1297606,-0.34576 0.2595213,-0.37673 0.3892818,-0.11953 0.1297606,0.2572 0.2595213,0.73474 0.3892819,0.99106 0.1297607,0.25631 0.2595213,0.25771 0.3892819,0.11953 0.1297606,-0.13818 0.2595212,-0.34402 0.3892819,-0.34419"
|
||||||
|
style="fill:none;fill-opacity:1;stroke:#04e2ff;stroke-width:0.43794215;stroke-linecap:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;paint-order:normal"
|
||||||
|
inkscape:connector-curvature="0" />
|
||||||
|
</g>
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 2.6 KiB |
83
Editor/resources/IconSongGroup.svg
Normal file
@@ -0,0 +1,83 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||||
|
<!-- Created with Inkscape (http://www.inkscape.org/) -->
|
||||||
|
|
||||||
|
<svg
|
||||||
|
xmlns:dc="http://purl.org/dc/elements/1.1/"
|
||||||
|
xmlns:cc="http://creativecommons.org/ns#"
|
||||||
|
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
|
||||||
|
xmlns:svg="http://www.w3.org/2000/svg"
|
||||||
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
|
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||||
|
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||||
|
width="16"
|
||||||
|
height="16"
|
||||||
|
viewBox="0 0 4.2333332 4.2333335"
|
||||||
|
id="svg2"
|
||||||
|
version="1.1"
|
||||||
|
inkscape:version="0.92.2 2405546, 2018-03-11"
|
||||||
|
sodipodi:docname="IconSongGroup.svg">
|
||||||
|
<defs
|
||||||
|
id="defs4" />
|
||||||
|
<sodipodi:namedview
|
||||||
|
id="base"
|
||||||
|
pagecolor="#393939"
|
||||||
|
bordercolor="#666666"
|
||||||
|
borderopacity="1.0"
|
||||||
|
inkscape:pageopacity="0"
|
||||||
|
inkscape:pageshadow="2"
|
||||||
|
inkscape:zoom="34.350339"
|
||||||
|
inkscape:cx="8.8858389"
|
||||||
|
inkscape:cy="8.8343343"
|
||||||
|
inkscape:document-units="px"
|
||||||
|
inkscape:current-layer="layer1"
|
||||||
|
showgrid="true"
|
||||||
|
units="px"
|
||||||
|
inkscape:window-width="1260"
|
||||||
|
inkscape:window-height="787"
|
||||||
|
inkscape:window-x="1944"
|
||||||
|
inkscape:window-y="288"
|
||||||
|
inkscape:window-maximized="0"
|
||||||
|
showborder="false"
|
||||||
|
objecttolerance="4"
|
||||||
|
gridtolerance="4"
|
||||||
|
guidetolerance="5">
|
||||||
|
<inkscape:grid
|
||||||
|
type="xygrid"
|
||||||
|
id="grid4173"
|
||||||
|
empspacing="1"
|
||||||
|
visible="true" />
|
||||||
|
</sodipodi:namedview>
|
||||||
|
<metadata
|
||||||
|
id="metadata7">
|
||||||
|
<rdf:RDF>
|
||||||
|
<cc:Work
|
||||||
|
rdf:about="">
|
||||||
|
<dc:format>image/svg+xml</dc:format>
|
||||||
|
<dc:type
|
||||||
|
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
|
||||||
|
<dc:title></dc:title>
|
||||||
|
</cc:Work>
|
||||||
|
</rdf:RDF>
|
||||||
|
</metadata>
|
||||||
|
<g
|
||||||
|
inkscape:label="Layer 1"
|
||||||
|
inkscape:groupmode="layer"
|
||||||
|
id="layer1"
|
||||||
|
transform="translate(0,-292.76665)">
|
||||||
|
<path
|
||||||
|
style="opacity:1;fill:#ff5599;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1.67643285;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
|
||||||
|
d="m 1.3229167,293.04538 c 0.2645833,0 0.5291666,0.25044 0.5291666,0.51502 l 0,0.26458 1.8488138,0.0102 c 0.3165926,0.002 0.5239173,0.20975 0.5245413,0.52471 l 0.00313,1.57936 c 6.239e-4,0.31495 -0.2079439,0.53411 -0.5245413,0.53411 l -3.17666623,0 C 0.21076252,296.47339 0,296.2566 0,295.94165 c 4.054e-5,-0.82258 0,-2.38125 0,-2.38125 0,-0.26458 0.26458333,-0.51612 0.52916667,-0.51612 z"
|
||||||
|
id="rect4141"
|
||||||
|
inkscape:connector-curvature="0"
|
||||||
|
sodipodi:nodetypes="cccssssscccc" />
|
||||||
|
<g
|
||||||
|
aria-label="♬"
|
||||||
|
style="font-style:normal;font-weight:normal;font-size:1.66674709px;line-height:1.25;font-family:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.31251505"
|
||||||
|
id="text820"
|
||||||
|
transform="matrix(1.1529095,0,0,1.1529095,-0.32840767,-44.985003)" />
|
||||||
|
<path
|
||||||
|
id="path868"
|
||||||
|
style="fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.26458332;stroke-miterlimit:4;stroke-dasharray:none"
|
||||||
|
d="m 1.8675862,295.87272 a 0.57456183,0.36088178 0 0 1 -0.5745618,0.36089 0.57456183,0.36088178 0 0 1 -0.57456171,-0.36089 0.57456183,0.36088178 0 0 1 0.57456171,-0.36088 0.57456183,0.36088178 0 0 1 0.5745618,0.36088 z m 1.3298265,-0.001 a 0.57456183,0.36088178 0 0 1 -0.5745619,0.36089 0.57456183,0.36088178 0 0 1 -0.5745618,-0.36089 0.57456183,0.36088178 0 0 1 0.5745618,-0.36088 0.57456183,0.36088178 0 0 1 0.5745619,0.36088 z m -0.253445,-1.78193 0.253445,0.006 v 1.77617 c -0.2177221,0.0701 -0.286996,-0.0173 -0.3755473,-0.1676 l 0.00387,-0.79478 H 1.868454 v 0.95424 c -0.2323614,-0.008 -0.2369279,-0.14254 -0.3755412,-0.22458 v -1.54879 z" />
|
||||||
|
</g>
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 3.6 KiB |
80
Editor/resources/IconSoundGroup.svg
Normal file
@@ -0,0 +1,80 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||||
|
<!-- Created with Inkscape (http://www.inkscape.org/) -->
|
||||||
|
|
||||||
|
<svg
|
||||||
|
xmlns:dc="http://purl.org/dc/elements/1.1/"
|
||||||
|
xmlns:cc="http://creativecommons.org/ns#"
|
||||||
|
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
|
||||||
|
xmlns:svg="http://www.w3.org/2000/svg"
|
||||||
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
|
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||||
|
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||||
|
width="16"
|
||||||
|
height="16"
|
||||||
|
viewBox="0 0 4.2333332 4.2333335"
|
||||||
|
id="svg2"
|
||||||
|
version="1.1"
|
||||||
|
inkscape:version="0.92.2 2405546, 2018-03-11"
|
||||||
|
sodipodi:docname="IconSoundGroup.svg">
|
||||||
|
<sodipodi:namedview
|
||||||
|
id="base"
|
||||||
|
pagecolor="#393939"
|
||||||
|
bordercolor="#666666"
|
||||||
|
borderopacity="1.0"
|
||||||
|
inkscape:pageopacity="0"
|
||||||
|
inkscape:pageshadow="2"
|
||||||
|
inkscape:zoom="34.25"
|
||||||
|
inkscape:cx="8.0808195"
|
||||||
|
inkscape:cy="8.452632"
|
||||||
|
inkscape:document-units="px"
|
||||||
|
inkscape:current-layer="layer1"
|
||||||
|
showgrid="true"
|
||||||
|
units="px"
|
||||||
|
inkscape:window-width="1258"
|
||||||
|
inkscape:window-height="787"
|
||||||
|
inkscape:window-x="1970"
|
||||||
|
inkscape:window-y="1150"
|
||||||
|
inkscape:window-maximized="0"
|
||||||
|
showborder="false"
|
||||||
|
objecttolerance="4"
|
||||||
|
gridtolerance="4"
|
||||||
|
guidetolerance="5">
|
||||||
|
<inkscape:grid
|
||||||
|
visible="true"
|
||||||
|
empspacing="1"
|
||||||
|
id="grid4173"
|
||||||
|
type="xygrid" />
|
||||||
|
</sodipodi:namedview>
|
||||||
|
<defs
|
||||||
|
id="defs4" />
|
||||||
|
<metadata
|
||||||
|
id="metadata7">
|
||||||
|
<rdf:RDF>
|
||||||
|
<cc:Work
|
||||||
|
rdf:about="">
|
||||||
|
<dc:format>image/svg+xml</dc:format>
|
||||||
|
<dc:type
|
||||||
|
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
|
||||||
|
<dc:title></dc:title>
|
||||||
|
</cc:Work>
|
||||||
|
</rdf:RDF>
|
||||||
|
</metadata>
|
||||||
|
<g
|
||||||
|
transform="translate(0,-292.76665)"
|
||||||
|
id="layer1"
|
||||||
|
inkscape:groupmode="layer"
|
||||||
|
inkscape:label="Layer 1">
|
||||||
|
<path
|
||||||
|
sodipodi:nodetypes="cccssssscccc"
|
||||||
|
inkscape:connector-curvature="0"
|
||||||
|
id="rect4141"
|
||||||
|
d="m 1.3229167,293.04538 c 0.2645833,0 0.5291666,0.25044 0.5291666,0.51502 l 0,0.26458 1.8488138,0.0102 c 0.3165926,0.002 0.5239173,0.20975 0.5245413,0.52471 l 0.00313,1.57936 c 6.239e-4,0.31495 -0.2079439,0.53411 -0.5245413,0.53411 l -3.17666623,0 C 0.21076252,296.47339 0,296.2566 0,295.94165 c 4.054e-5,-0.82258 0,-2.38125 0,-2.38125 0,-0.26458 0.26458333,-0.51612 0.52916667,-0.51612 z"
|
||||||
|
style="opacity:1;fill:#04e2ff;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1.67643285;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" />
|
||||||
|
<path
|
||||||
|
id="path1184"
|
||||||
|
title="sin(x*4*pi)*sin(x*pi)"
|
||||||
|
d="m 0.52916698,295.1479 c 0.11759258,-1.5e-4 0.23518516,-0.18652 0.35277775,-0.31191 0.11759258,-0.1254 0.23518517,-0.1236 0.35277777,0.10832 0.1175926,0.23193 0.2351851,0.66463 0.3527777,0.89812 0.1175926,0.23349 0.2351852,0.20457 0.3527778,-0.10832 0.1175925,-0.3129 0.2351851,-0.85907 0.3527777,-1.17242 0.1175926,-0.31334 0.2351852,-0.3414 0.3527777,-0.10832 0.1175926,0.23308 0.2351852,0.66584 0.3527778,0.89812 0.1175926,0.23228 0.2351852,0.23355 0.3527777,0.10832 0.1175926,-0.12522 0.2351852,-0.31176 0.3527778,-0.31191"
|
||||||
|
style="fill:none;fill-opacity:1;stroke:#000000;stroke-width:0.396875;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;stroke-linecap:round;paint-order:normal"
|
||||||
|
inkscape:connector-curvature="0" />
|
||||||
|
</g>
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 3.3 KiB |
74
Editor/resources/IconSoundMacro.svg
Normal file
@@ -0,0 +1,74 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||||
|
<!-- Created with Inkscape (http://www.inkscape.org/) -->
|
||||||
|
|
||||||
|
<svg
|
||||||
|
xmlns:dc="http://purl.org/dc/elements/1.1/"
|
||||||
|
xmlns:cc="http://creativecommons.org/ns#"
|
||||||
|
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
|
||||||
|
xmlns:svg="http://www.w3.org/2000/svg"
|
||||||
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
|
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||||
|
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||||
|
width="16"
|
||||||
|
height="16"
|
||||||
|
viewBox="0 0 4.2333332 4.2333335"
|
||||||
|
id="svg2"
|
||||||
|
version="1.1"
|
||||||
|
inkscape:version="0.92.2 2405546, 2018-03-11"
|
||||||
|
sodipodi:docname="IconSoundMacro.svg">
|
||||||
|
<defs
|
||||||
|
id="defs4" />
|
||||||
|
<sodipodi:namedview
|
||||||
|
id="base"
|
||||||
|
pagecolor="#393939"
|
||||||
|
bordercolor="#666666"
|
||||||
|
borderopacity="1.0"
|
||||||
|
inkscape:pageopacity="0"
|
||||||
|
inkscape:pageshadow="2"
|
||||||
|
inkscape:zoom="49.27"
|
||||||
|
inkscape:cx="6.2572034"
|
||||||
|
inkscape:cy="5.0825963"
|
||||||
|
inkscape:document-units="px"
|
||||||
|
inkscape:current-layer="layer1"
|
||||||
|
showgrid="true"
|
||||||
|
units="px"
|
||||||
|
inkscape:window-width="1260"
|
||||||
|
inkscape:window-height="787"
|
||||||
|
inkscape:window-x="0"
|
||||||
|
inkscape:window-y="40"
|
||||||
|
inkscape:window-maximized="0"
|
||||||
|
showborder="false"
|
||||||
|
objecttolerance="4"
|
||||||
|
gridtolerance="4"
|
||||||
|
guidetolerance="5">
|
||||||
|
<inkscape:grid
|
||||||
|
type="xygrid"
|
||||||
|
id="grid4173"
|
||||||
|
empspacing="1"
|
||||||
|
visible="true" />
|
||||||
|
</sodipodi:namedview>
|
||||||
|
<metadata
|
||||||
|
id="metadata7">
|
||||||
|
<rdf:RDF>
|
||||||
|
<cc:Work
|
||||||
|
rdf:about="">
|
||||||
|
<dc:format>image/svg+xml</dc:format>
|
||||||
|
<dc:type
|
||||||
|
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
|
||||||
|
<dc:title></dc:title>
|
||||||
|
</cc:Work>
|
||||||
|
</rdf:RDF>
|
||||||
|
</metadata>
|
||||||
|
<g
|
||||||
|
inkscape:label="Layer 1"
|
||||||
|
inkscape:groupmode="layer"
|
||||||
|
id="layer1"
|
||||||
|
transform="translate(0,-292.76665)">
|
||||||
|
<path
|
||||||
|
style="opacity:1;fill:#62ff04;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:0.30031049;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
|
||||||
|
d="m 0.96793039,292.83382 2.60268711,1.68348 c 0.392506,0.24382 0.3952842,0.49652 0,0.73535 l -2.60268711,1.69163 c -0.27899363,0.18133 -0.60063679,-0.0548 -0.60063679,-0.39294 l 0,-3.35322 c 0,-0.33276 0.32123948,-0.54502 0.60063679,-0.3643 z"
|
||||||
|
id="rect5899"
|
||||||
|
inkscape:connector-curvature="0"
|
||||||
|
sodipodi:nodetypes="sccssss" />
|
||||||
|
</g>
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 2.4 KiB |
78
Editor/resources/IconSoundMacroDelete.svg
Normal file
@@ -0,0 +1,78 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||||
|
<!-- Created with Inkscape (http://www.inkscape.org/) -->
|
||||||
|
|
||||||
|
<svg
|
||||||
|
xmlns:dc="http://purl.org/dc/elements/1.1/"
|
||||||
|
xmlns:cc="http://creativecommons.org/ns#"
|
||||||
|
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
|
||||||
|
xmlns:svg="http://www.w3.org/2000/svg"
|
||||||
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
|
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||||
|
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||||
|
width="20"
|
||||||
|
height="20"
|
||||||
|
viewBox="0 0 5.2916665 5.2916668"
|
||||||
|
version="1.1"
|
||||||
|
id="svg8"
|
||||||
|
inkscape:version="0.92.2 2405546, 2018-03-11"
|
||||||
|
sodipodi:docname="IconSoundMacroDelete.svg">
|
||||||
|
<defs
|
||||||
|
id="defs2" />
|
||||||
|
<sodipodi:namedview
|
||||||
|
id="base"
|
||||||
|
pagecolor="#7f7f7f"
|
||||||
|
bordercolor="#666666"
|
||||||
|
borderopacity="1.0"
|
||||||
|
inkscape:pageopacity="0"
|
||||||
|
inkscape:pageshadow="2"
|
||||||
|
inkscape:zoom="16.12"
|
||||||
|
inkscape:cx="4.9858624"
|
||||||
|
inkscape:cy="10.149308"
|
||||||
|
inkscape:document-units="px"
|
||||||
|
inkscape:current-layer="layer1"
|
||||||
|
showgrid="true"
|
||||||
|
units="px"
|
||||||
|
inkscape:window-width="1280"
|
||||||
|
inkscape:window-height="877"
|
||||||
|
inkscape:window-x="80"
|
||||||
|
inkscape:window-y="214"
|
||||||
|
inkscape:window-maximized="0">
|
||||||
|
<inkscape:grid
|
||||||
|
type="xygrid"
|
||||||
|
id="grid817"
|
||||||
|
empspacing="0"
|
||||||
|
spacingx="0.52916666"
|
||||||
|
spacingy="0.52916666"
|
||||||
|
visible="true" />
|
||||||
|
</sodipodi:namedview>
|
||||||
|
<metadata
|
||||||
|
id="metadata5">
|
||||||
|
<rdf:RDF>
|
||||||
|
<cc:Work
|
||||||
|
rdf:about="">
|
||||||
|
<dc:format>image/svg+xml</dc:format>
|
||||||
|
<dc:type
|
||||||
|
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
|
||||||
|
<dc:title></dc:title>
|
||||||
|
</cc:Work>
|
||||||
|
</rdf:RDF>
|
||||||
|
</metadata>
|
||||||
|
<g
|
||||||
|
inkscape:label="Layer 1"
|
||||||
|
inkscape:groupmode="layer"
|
||||||
|
id="layer1"
|
||||||
|
transform="translate(0,-291.70832)">
|
||||||
|
<path
|
||||||
|
style="fill:none;stroke:#353535;stroke-width:0.52916664;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
|
||||||
|
d="m 1.0583333,292.76665 3.175,3.175"
|
||||||
|
id="path10"
|
||||||
|
inkscape:connector-curvature="0"
|
||||||
|
sodipodi:nodetypes="cc" />
|
||||||
|
<path
|
||||||
|
sodipodi:nodetypes="cc"
|
||||||
|
inkscape:connector-curvature="0"
|
||||||
|
id="path819"
|
||||||
|
d="m 4.2333333,292.76665 -3.175,3.175"
|
||||||
|
style="fill:none;stroke:#353535;stroke-width:0.52916664;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" />
|
||||||
|
</g>
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 2.4 KiB |
78
Editor/resources/IconSoundMacroDeleteHovered.svg
Normal file
@@ -0,0 +1,78 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||||
|
<!-- Created with Inkscape (http://www.inkscape.org/) -->
|
||||||
|
|
||||||
|
<svg
|
||||||
|
xmlns:dc="http://purl.org/dc/elements/1.1/"
|
||||||
|
xmlns:cc="http://creativecommons.org/ns#"
|
||||||
|
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
|
||||||
|
xmlns:svg="http://www.w3.org/2000/svg"
|
||||||
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
|
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||||
|
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||||
|
width="20"
|
||||||
|
height="20"
|
||||||
|
viewBox="0 0 5.2916665 5.2916668"
|
||||||
|
version="1.1"
|
||||||
|
id="svg8"
|
||||||
|
inkscape:version="0.92.2 2405546, 2018-03-11"
|
||||||
|
sodipodi:docname="IconSoundMacroDeleteHovered.svg">
|
||||||
|
<defs
|
||||||
|
id="defs2" />
|
||||||
|
<sodipodi:namedview
|
||||||
|
id="base"
|
||||||
|
pagecolor="#7f7f7f"
|
||||||
|
bordercolor="#666666"
|
||||||
|
borderopacity="1.0"
|
||||||
|
inkscape:pageopacity="0"
|
||||||
|
inkscape:pageshadow="2"
|
||||||
|
inkscape:zoom="64.48"
|
||||||
|
inkscape:cx="3.5548908"
|
||||||
|
inkscape:cy="13.722588"
|
||||||
|
inkscape:document-units="px"
|
||||||
|
inkscape:current-layer="layer1"
|
||||||
|
showgrid="true"
|
||||||
|
units="px"
|
||||||
|
inkscape:window-width="3840"
|
||||||
|
inkscape:window-height="2033"
|
||||||
|
inkscape:window-x="0"
|
||||||
|
inkscape:window-y="66"
|
||||||
|
inkscape:window-maximized="1">
|
||||||
|
<inkscape:grid
|
||||||
|
type="xygrid"
|
||||||
|
id="grid817"
|
||||||
|
empspacing="0"
|
||||||
|
spacingx="0.52916666"
|
||||||
|
spacingy="0.52916666"
|
||||||
|
visible="true" />
|
||||||
|
</sodipodi:namedview>
|
||||||
|
<metadata
|
||||||
|
id="metadata5">
|
||||||
|
<rdf:RDF>
|
||||||
|
<cc:Work
|
||||||
|
rdf:about="">
|
||||||
|
<dc:format>image/svg+xml</dc:format>
|
||||||
|
<dc:type
|
||||||
|
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
|
||||||
|
<dc:title />
|
||||||
|
</cc:Work>
|
||||||
|
</rdf:RDF>
|
||||||
|
</metadata>
|
||||||
|
<g
|
||||||
|
inkscape:label="Layer 1"
|
||||||
|
inkscape:groupmode="layer"
|
||||||
|
id="layer1"
|
||||||
|
transform="translate(0,-291.70832)">
|
||||||
|
<path
|
||||||
|
style="fill:none;stroke:#9c0000;stroke-width:0.52916664;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
|
||||||
|
d="m 1.0583333,292.76665 3.175,3.175"
|
||||||
|
id="path10"
|
||||||
|
inkscape:connector-curvature="0"
|
||||||
|
sodipodi:nodetypes="cc" />
|
||||||
|
<path
|
||||||
|
sodipodi:nodetypes="cc"
|
||||||
|
inkscape:connector-curvature="0"
|
||||||
|
id="path819"
|
||||||
|
d="m 4.2333333,292.76665 -3.175,3.175"
|
||||||
|
style="fill:none;stroke:#9c0000;stroke-width:0.52916664;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" />
|
||||||
|
</g>
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 2.4 KiB |