mirror of
https://github.com/Artemis-RGB/Artemis
synced 2025-12-12 13:28:33 +00:00
Merge branch 'development'
This commit is contained in:
commit
ef08000f56
3
.gitignore
vendored
3
.gitignore
vendored
@ -198,4 +198,5 @@ src/Artemis\.Storage/Storage\.db
|
||||
docfx/docfx_project/_site/
|
||||
|
||||
src/.idea/
|
||||
packages.lock.json
|
||||
packages.lock.json
|
||||
docfx/docfx_project/api/
|
||||
|
||||
5
docfx/docfx_project/api/.gitignore
vendored
5
docfx/docfx_project/api/.gitignore
vendored
@ -1,5 +0,0 @@
|
||||
###############
|
||||
# temp file #
|
||||
###############
|
||||
*.yml
|
||||
.manifest
|
||||
@ -1,26 +0,0 @@
|
||||
|
||||
# Welcome to the **Artemis API documentation**
|
||||
On this website you can browse the Artemis Core and Shared UI API.
|
||||
A large part of this documentation is being generated based on code but over time the plan is to expand the documentation with written guides.
|
||||
|
||||
|
||||
## Plugins
|
||||
Artemis 2.0 has been developed from the ground up with plugins in mind. This means almost all functionality can be expanded. The following plugin types are currently available and fully implemented:
|
||||
- [DeviceProvider](api/Artemis.Core.DeviceProviders.DeviceProvider.html)
|
||||
- [LayerBrush\<T\>](api/Artemis.Core.LayerBrushes.LayerBrush-1.html)
|
||||
- [PerLedLayerBrush\<T\>](api/Artemis.Core.LayerBrushes.PerLedLayerBrush-1.html)
|
||||
- [LayerEffect](api/Artemis.Core.LayerEffects.LayerEffect-1.html)
|
||||
- [Module](api/Artemis.Core.Modules.Module.html)
|
||||
- [Module\<T\>](api/Artemis.Core.Modules.Module-1.html)
|
||||
|
||||
These allow you to expand on Artemis's functionality. For quick and interactive plugin creation, use the [Visual Studio template extension](https://marketplace.visualstudio.com/items?itemName=SpoinkyNL.ArtemisTemplates).
|
||||
|
||||
Example implementations of these plugins can be found on [GitHub](https://github.com/Artemis-RGB/Artemis/tree/master/src/Plugins).
|
||||
|
||||
## Services
|
||||
Artemis provides plugins with an API through a range of services.
|
||||
All the services are available to plugins by using dependency injection in your plugin's constructor. Dependency injection is also available for the different view models plugins may provide.
|
||||
|
||||
- [Core Services](api/Artemis.Core.Services.html#interfaces)
|
||||
- [UI Services](api/Artemis.UI.Shared.Services.html#interfaces)
|
||||
|
||||
4
docfx/docfx_project/artemis-template/public/main.css
Normal file
4
docfx/docfx_project/artemis-template/public/main.css
Normal file
@ -0,0 +1,4 @@
|
||||
#logo {
|
||||
height: 40px;
|
||||
margin-right: 10px;
|
||||
}
|
||||
@ -3,30 +3,26 @@
|
||||
{
|
||||
"src": [
|
||||
{
|
||||
"src": "../../src",
|
||||
"files": [
|
||||
"Artemis.Core/bin/net7.0/Artemis.Core.dll",
|
||||
"Artemis.UI.Shared/bin/net7.0/Artemis.UI.Shared.dll"
|
||||
],
|
||||
"src": "../../src"
|
||||
"**/Artemis.Core.csproj",
|
||||
"**/Artemis.UI.Shared.csproj"
|
||||
]
|
||||
}
|
||||
],
|
||||
"dest": "api",
|
||||
"disableGitFeatures": false,
|
||||
"disableDefaultFilter": false,
|
||||
"filter": "filterConfig.yml"
|
||||
"filter": "filterConfig.yml",
|
||||
"namespaceLayout": "nested"
|
||||
}
|
||||
],
|
||||
"build": {
|
||||
"content": [
|
||||
{
|
||||
"files": [
|
||||
"api/**.yml"
|
||||
]
|
||||
},
|
||||
{
|
||||
"files": [
|
||||
"toc.yml",
|
||||
"*.md"
|
||||
"**/*.{md,yml}"
|
||||
],
|
||||
"exclude": [
|
||||
"_site/**"
|
||||
]
|
||||
}
|
||||
],
|
||||
@ -37,42 +33,23 @@
|
||||
]
|
||||
}
|
||||
],
|
||||
"overwrite": [
|
||||
{
|
||||
"files": [
|
||||
"apidoc/**.md"
|
||||
],
|
||||
"exclude": [
|
||||
"obj/**",
|
||||
"_site/**"
|
||||
]
|
||||
}
|
||||
"output": "_site",
|
||||
"template": [
|
||||
"default",
|
||||
"modern",
|
||||
"artemis-template"
|
||||
],
|
||||
"globalMetadata": {
|
||||
"_appTitle": "Artemis API Documentation",
|
||||
"_appName": "Artemis",
|
||||
"_appFaviconPath": "images/application.ico",
|
||||
"_appLogoPath": "images/application.ico",
|
||||
"_appFooter": "<a href=\"https://artemis-rgb.com\" style=\"margin: 0 5px;\">\r <i class=\"bi-globe\" role=\"img\" aria-label=\"GitHub\" style=\"margin: 0 10\"></i>\r</a>\r<a href=\"https://github.com/Artemis-RGB/Artemis\" style=\"margin: 0 5px;\">\r <i class=\"bi-github\" role=\"img\" aria-label=\"GitHub\"></i>\r</a>\r<a href=\"https://artemis-rgb.com\" style=\"margin: 0 5px;\">\r <i class=\"bi bi-layout-text-sidebar-reverse\" role=\"img\" aria-label=\"GitHub\"></i>\r</a>\r<a href=\"https://wiki.artemis-rgb.com/\" style=\"margin: 0 5px;\">\r <i class=\"bi-chat-fill\" role=\"img\" aria-label=\"GitHub\"></i>\r</a>\r<a href=\"https://wiki.artemis-rgb.com/en/donating\" style=\"margin: 0 5px;\">\r <i class=\"bi-gift-fill\" role=\"img\" aria-label=\"GitHub\"></i>\r</a>",
|
||||
"_appFaviconPath": "images/application.ico",
|
||||
"_copyrightFooter": "Content is available under the PolyForm Noncommercial License, by Artemis RGB.",
|
||||
"_enableSearch": true,
|
||||
"_disableSideFilter": false,
|
||||
"_enableNewTab": true,
|
||||
"_disableContribution": false,
|
||||
"_disableBreadcrumb": false
|
||||
},
|
||||
"dest": "_site",
|
||||
"globalMetadataFiles": [],
|
||||
"fileMetadataFiles": [],
|
||||
"template": [
|
||||
"default",
|
||||
"templates/singulinkfx"
|
||||
],
|
||||
"postProcessors": [],
|
||||
"markdownEngineName": "markdig",
|
||||
"noLangKeyword": false,
|
||||
"keepFileLink": false,
|
||||
"cleanupCacheHistory": false,
|
||||
"disableGitFeatures": false
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -24,5 +24,5 @@ apiRules:
|
||||
uidRegex: ^Artemis\.UI\.Shared\.Properties
|
||||
type: Type
|
||||
- exclude:
|
||||
uidRegex: ^Artemis\.Core\.TypeExtensions\.IsNumber
|
||||
type: Method
|
||||
uidRegex: ^Artemis\.Core\.TypeExtensions
|
||||
type: Type
|
||||
@ -1,26 +1,7 @@
|
||||
---
|
||||
_layout: landing
|
||||
---
|
||||
|
||||
# Welcome to the **Artemis API documentation**
|
||||
On this website you can browse the Artemis Core and Shared UI API.
|
||||
A large part of this documentation is being generated based on code but over time the plan is to expand the documentation with written guides.
|
||||
|
||||
|
||||
## Plugins
|
||||
Artemis 2.0 has been developed from the ground up with plugins in mind. This means almost all functionality can be expanded. The following plugin types are currently available and fully implemented:
|
||||
- [DeviceProvider](api/Artemis.Core.DeviceProviders.DeviceProvider.html)
|
||||
- [LayerBrush\<T\>](api/Artemis.Core.LayerBrushes.LayerBrush-1.html)
|
||||
- [PerLedLayerBrush\<T\>](api/Artemis.Core.LayerBrushes.PerLedLayerBrush-1.html)
|
||||
- [LayerEffect](api/Artemis.Core.LayerEffects.LayerEffect-1.html)
|
||||
- [Module](api/Artemis.Core.Modules.Module.html)
|
||||
- [Module\<T\>](api/Artemis.Core.Modules.Module-1.html)
|
||||
|
||||
These allow you to expand on Artemis's functionality. For quick and interactive plugin creation, use the [Visual Studio template extension](https://marketplace.visualstudio.com/items?itemName=SpoinkyNL.ArtemisTemplates).
|
||||
|
||||
Example implementations of these plugins can be found on [GitHub](https://github.com/Artemis-RGB/Artemis/tree/master/src/Plugins).
|
||||
|
||||
## Services
|
||||
Artemis provides plugins with an API through a range of services.
|
||||
All the services are available to plugins by using dependency injection in your plugin's constructor. Dependency injection is also available for the different view models plugins may provide.
|
||||
|
||||
- [Core Services](api/Artemis.Core.Services.html#interfaces)
|
||||
- [UI Services](api/Artemis.UI.Shared.Services.html#interfaces)
|
||||
|
||||
# Artemis Technical Documentation
|
||||
Welcome to the technical docs of Artemis. This page contains all the public types available when writing Artemis plugins.
|
||||
For more details, please refer to the [Artemis wiki](https://wiki.artemis-rgb.com/en/guides/developer).
|
||||
@ -1,62 +0,0 @@
|
||||
{{!Copyright (c) Microsoft. All rights reserved. Licensed under the MIT license. See LICENSE file in the project root for full license information.}}
|
||||
{{!include(/^styles/.*/)}}
|
||||
{{!include(/^fonts/.*/)}}
|
||||
{{!include(favicon.ico)}}
|
||||
{{!include(logo.svg)}}
|
||||
{{!include(search-stopwords.json)}}
|
||||
<!DOCTYPE html>
|
||||
<!--[if IE]><![endif]-->
|
||||
<html>
|
||||
{{>partials/head}}
|
||||
|
||||
<body>
|
||||
<div class="top-navbar">
|
||||
<a class="burger-icon" onclick="toggleMenu()">
|
||||
<svg name="Hamburger"
|
||||
style="vertical-align: middle;"
|
||||
width="34" height="34" viewBox="0 0 24 24"><path fill="currentColor" fill-rule="evenodd" clip-rule="evenodd" d="M20 6H4V9H20V6ZM4 10.999H20V13.999H4V10.999ZM4 15.999H20V18.999H4V15.999Z"></path></svg>
|
||||
</a>
|
||||
|
||||
{{>partials/logo}}
|
||||
</div>
|
||||
|
||||
<div class="body-content">
|
||||
<div id="blackout" class="blackout" onclick="toggleMenu()"></div>
|
||||
|
||||
<nav id="sidebar" role="navigation">
|
||||
<div class="sidebar">
|
||||
{{>partials/navbar}}
|
||||
<div class="sidebar-item-separator"></div>
|
||||
{{^_disableToc}}
|
||||
{{>partials/toc}}
|
||||
{{/_disableToc}}
|
||||
</div>
|
||||
{{>partials/footer}}
|
||||
</nav>
|
||||
|
||||
<main class="main-panel">
|
||||
{{#_enableSearch}}
|
||||
{{>partials/searchResults}}
|
||||
{{/_enableSearch}}
|
||||
|
||||
<div role="main" class="hide-when-search" >
|
||||
{{^_disableBreadcrumb}}
|
||||
{{>partials/breadcrumb}}
|
||||
{{/_disableBreadcrumb}}
|
||||
|
||||
<article class="content wrap" id="_content" data-uid="{{uid}}">
|
||||
{{!body}}
|
||||
</article>
|
||||
</div>
|
||||
|
||||
{{#_copyrightFooter}}
|
||||
<div class="copyright-footer">
|
||||
<span>{{_copyrightFooter}}</span>
|
||||
</div>
|
||||
{{/_copyrightFooter}}
|
||||
</main>
|
||||
</div>
|
||||
|
||||
{{>partials/scripts}}
|
||||
</body>
|
||||
</html>
|
||||
@ -1,4 +0,0 @@
|
||||
<div class="footer">
|
||||
{{{_appFooter}}}
|
||||
{{^_appFooter}}<strong><a href='https://dotnet.github.io/docfx/'>DocFX</a> + <a href='https://www.singulink.com'>Singulink</a> = ♥</strong>{{/_appFooter}}
|
||||
</div>
|
||||
@ -1,24 +0,0 @@
|
||||
{{!Copyright (c) Microsoft. All rights reserved. Licensed under the MIT license. See LICENSE file in the project root for full license information.}}
|
||||
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
|
||||
<title>{{#title}}{{title}}{{/title}}{{^title}}{{>partials/title}}{{/title}} {{#_appTitle}}| {{_appTitle}} {{/_appTitle}}</title>
|
||||
<meta name="viewport" content="width=device-width">
|
||||
<meta name="title" content="{{#title}}{{title}}{{/title}}{{^title}}{{>partials/title}}{{/title}} {{#_appTitle}}| {{_appTitle}} {{/_appTitle}}">
|
||||
<meta name="generator" content="docfx {{_docfxVersion}}">
|
||||
{{#_description}}<meta name="description" content="{{_description}}">{{/_description}}
|
||||
<link rel="shortcut icon" href="{{_rel}}{{{_appFaviconPath}}}{{^_appFaviconPath}}favicon.ico{{/_appFaviconPath}}">
|
||||
<link href="https://fonts.googleapis.com/css2?family=Roboto:wght@300;400;500;700&display=swap" rel="stylesheet">
|
||||
<link rel="stylesheet" href="//cdnjs.cloudflare.com/ajax/libs/highlight.js/10.1.1/styles/night-owl.min.css">
|
||||
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap-icons@1.7.2/font/bootstrap-icons.css" integrity="sha384-EvBWSlnoFgZlXJvpzS+MAUEjvN7+gcCwH+qh7GRFOGgZO0PuwOFro7qPOJnLfe7l" crossorigin="anonymous">
|
||||
<link rel="stylesheet" href="{{_rel}}styles/config.css">
|
||||
<link rel="stylesheet" href="{{_rel}}styles/discord.css">
|
||||
<link rel="stylesheet" href="{{_rel}}styles/singulink.css">
|
||||
<link rel="stylesheet" href="{{_rel}}styles/main.css">
|
||||
<meta property="docfx:navrel" content="{{_navRel}}">
|
||||
<meta property="docfx:tocrel" content="{{_tocRel}}">
|
||||
{{#_noindex}}<meta name="searchOption" content="noindex">{{/_noindex}}
|
||||
{{#_enableSearch}}<meta property="docfx:rel" content="{{_rel}}">{{/_enableSearch}}
|
||||
{{#_enableNewTab}}<meta property="docfx:newtab" content="true">{{/_enableNewTab}}
|
||||
</head>
|
||||
@ -1,31 +0,0 @@
|
||||
{{!Copyright (c) Microsoft. All rights reserved. Licensed under the MIT license. See LICENSE file in the project root for full license information.}}
|
||||
|
||||
<ul class="nav level{{level}}">
|
||||
{{#items}}
|
||||
{{^dropdown}}
|
||||
<li>
|
||||
{{^leaf}}
|
||||
<span class="expand-stub"></span>
|
||||
{{/leaf}}
|
||||
{{#topicHref}}
|
||||
<a href="{{topicHref}}" class="sidebar-item" name="{{tocHref}}" title="{{name}}">{{name}}</a>
|
||||
{{/topicHref}}
|
||||
{{^topicHref}}
|
||||
<a>{{{name}}}</a>
|
||||
{{/topicHref}}
|
||||
|
||||
{{^leaf}}
|
||||
{{>partials/li}}
|
||||
{{/leaf}}
|
||||
</li>
|
||||
{{/dropdown}}
|
||||
{{#dropdown}}
|
||||
<li class="dropdown">
|
||||
<a class="dropdown-toggle" data-toggle="dropdown" href="#" role="button" aria-haspopup="true" aria-expanded="false">{{name}} <span class="caret"></span></a>
|
||||
<ul class="dropdown-menu level{{level}}">
|
||||
{{>partials/dd-li}}
|
||||
</ul>
|
||||
</li>
|
||||
{{/dropdown}}
|
||||
{{/items}}
|
||||
</ul>
|
||||
@ -1,6 +0,0 @@
|
||||
{{!Copyright (c) Microsoft. All rights reserved. Licensed under the MIT license. See LICENSE file in the project root for full license information.}}
|
||||
|
||||
<a class="brand" href="{{_rel}}index.html">
|
||||
<img src="{{_rel}}{{{_appLogoPath}}}{{^_appLogoPath}}logo.svg{{/_appLogoPath}}" alt="{{_appName}}" class="logomark">
|
||||
<span class="brand-title">{{_appName}}</span>
|
||||
</a>
|
||||
@ -1,13 +0,0 @@
|
||||
{{!Copyright (c) Microsoft. All rights reserved. Licensed under the MIT license. See LICENSE file in the project root for full license information.}}
|
||||
|
||||
<h1 id="{{id}}" data-uid="{{uid}}" class="text-break">{{>partials/title}}</h1>
|
||||
<div class="markdown level0 summary">{{{summary}}}</div>
|
||||
<div class="markdown level0 conceptual">{{{conceptual}}}</div>
|
||||
<div class="markdown level0 remarks">{{{remarks}}}</div>
|
||||
{{#children}}
|
||||
<h3 id="{{id}}">{{>partials/namespaceSubtitle}}</h3>
|
||||
{{#children}}
|
||||
<h5><xref uid="{{uid}}" altProperty="fullName" displayProperty="name"/></h5>
|
||||
<section>{{{summary}}}</section>
|
||||
{{/children}}
|
||||
{{/children}}
|
||||
@ -1,19 +0,0 @@
|
||||
{{!Copyright (c) Microsoft. All rights reserved. Licensed under the MIT license. See LICENSE file in the project root for full license information.}}
|
||||
|
||||
<div>
|
||||
<div class="mobile-hide">
|
||||
{{>partials/logo}}
|
||||
</div>
|
||||
|
||||
{{#_enableSearch}}
|
||||
<div class="sidesearch">
|
||||
<form id="search" role="search" class="search">
|
||||
<i class="bi bi-search search-icon"></i>
|
||||
<input type="text" id="search-query" placeholder="{{__global.search}}" autocomplete="off">
|
||||
</form>
|
||||
</div>
|
||||
{{/_enableSearch}}
|
||||
|
||||
<div id="navbar">
|
||||
</div>
|
||||
</div>
|
||||
@ -1,12 +0,0 @@
|
||||
{{!Copyright (c) Microsoft. All rights reserved. Licensed under the MIT license. See LICENSE file in the project root for full license information.}}
|
||||
|
||||
<script src="https://code.jquery.com/jquery-3.5.1.min.js" integrity="sha256-9/aliU8dGd2tb6OSsuzixeV4y/faTqgFtohetphbbj0=" crossorigin="anonymous"></script>
|
||||
<script src="https://cdn.jsdelivr.net/npm/popper.js@1.16.0/dist/umd/popper.min.js" integrity="sha384-Q6E9RHvbIyZFJoft+2mJbHaEWldlvI9IOYy5n3zV9zzTtmI3UksdQRVvoxMfooAo" crossorigin="anonymous"></script>
|
||||
<script src="https://stackpath.bootstrapcdn.com/bootstrap/4.5.0/js/bootstrap.min.js" integrity="sha384-OgVRvuATP1z7JjHLkuOU7Xw704+h835Lr+6QL9UvYjZE3Ipu6Tp75j7Bh/kR0JKI" crossorigin="anonymous"></script>
|
||||
<script src="//cdnjs.cloudflare.com/ajax/libs/highlight.js/10.1.1/highlight.min.js"></script>
|
||||
<script type="text/javascript" src="{{_rel}}styles/jquery.twbsPagination.js"></script>
|
||||
<script type="text/javascript" src="{{_rel}}styles/url.min.js"></script>
|
||||
<script src="https://cdn.jsdelivr.net/npm/anchor-js/anchor.min.js"></script>
|
||||
<script type="text/javascript" src="{{_rel}}styles/docfx.js"></script>
|
||||
<script type="text/javascript" src="{{_rel}}styles/singulink.js"></script>
|
||||
<script type="text/javascript" src="{{_rel}}styles/main.js"></script>
|
||||
@ -1,9 +0,0 @@
|
||||
{{!Copyright (c) Microsoft. All rights reserved. Licensed under the MIT license. See LICENSE file in the project root for full license information.}}
|
||||
|
||||
<div id="search-results" style="display: none;">
|
||||
<h1 class="search-list">{{__global.searchResults}} <span></span></h1>
|
||||
<div class="sr-items">
|
||||
<p><i class="bi bi-hourglass-split index-loading"></i></p>
|
||||
</div>
|
||||
<ul id="pagination" data-first={{__global.pageFirst}} data-prev={{__global.pagePrev}} data-next={{__global.pageNext}} data-last={{__global.pageLast}}></ul>
|
||||
</div>
|
||||
@ -1,5 +0,0 @@
|
||||
{{!Copyright (c) Microsoft. All rights reserved. Licensed under the MIT license. See LICENSE file in the project root for full license information.}}
|
||||
|
||||
<div id="sidetoggle">
|
||||
<div id="sidetoc"></div>
|
||||
</div>
|
||||
@ -1,114 +0,0 @@
|
||||
/* Theme Configuration Options */
|
||||
|
||||
:root
|
||||
{
|
||||
/* General */
|
||||
|
||||
--base-font-size: 16px;
|
||||
--smalldevice-base-font-size: 14px; /* Base font size for devices < 1024px */
|
||||
|
||||
--main-bg-color: #1f1f23;
|
||||
--footer-bg-color: rgba(0,0,0,.4);
|
||||
--separator-color: #42474f;
|
||||
|
||||
--table-strip-bg-color: #151515;
|
||||
--table-header-bg-color: black;
|
||||
--table-header-color: hsla(0,0%,100%,.8);
|
||||
--table-header-border-color: #040405;
|
||||
|
||||
/* Text */
|
||||
|
||||
--appname-color: white;
|
||||
|
||||
--h1-color: white;
|
||||
--h2-color: #f2f2f2;
|
||||
--h3-color: #e3e3e3;
|
||||
--h4-color: #ffffff;
|
||||
--h5-color: #e0e0e0;
|
||||
|
||||
--text-color: #e1e1e1;
|
||||
--link-color: #00b0f4;
|
||||
--link-hover-color: #2ec4ff;
|
||||
|
||||
/* Mobile Topbar */
|
||||
|
||||
--topbar-bg-color: #18191c;
|
||||
|
||||
/* Button */
|
||||
|
||||
--button-color: #747f8d;
|
||||
|
||||
/* Sidebar */
|
||||
|
||||
--sidebar-width: 400px;
|
||||
--sidebar-bg-color: #292B30;
|
||||
|
||||
--search-color: #bdbdbd;
|
||||
--search-bg-color: #1b1e21;
|
||||
--search-searchicon-color: #e3e3e3;
|
||||
--search-border-color: black;
|
||||
|
||||
--sidebar-item-color: white;
|
||||
--sidebar-active-item-color: #00b0f4;
|
||||
--sidebar-level1-item-bg-color: #222429;
|
||||
--sidebar-level1-item-hover-bg-color: #1D1F22;
|
||||
|
||||
--toc-filter-color: #bdbdbd;
|
||||
--toc-filter-bg-color: #1b1e21;
|
||||
--toc-filter-filtericon-color: #e3e3e3;
|
||||
--toc-filter-clearicon-color: #e68585;
|
||||
--toc-filter-border-color: black;
|
||||
|
||||
/* Scrollbars */
|
||||
|
||||
--scrollbar-bg-color: transparent;
|
||||
--scrollbar-thumb-bg-color: rgba(0,0,0,.4);
|
||||
--scrollbar-thumb-border-color: transparent;
|
||||
|
||||
/* Alerts and Blocks */
|
||||
|
||||
--alert-info-border-color: rgba(114,137,218,.5);
|
||||
--alert-info-bg-color: rgba(114,137,218,.1);
|
||||
|
||||
--alert-warning-border-color: rgba(250,166,26,.5);
|
||||
--alert-warning-bg-color: rgba(250,166,26,.1);
|
||||
|
||||
--alert-danger-border-color: rgba(240,71,71,.5);
|
||||
--alert-danger-bg-color: rgba(240,71,71,.1);
|
||||
|
||||
--alert-tip-border-color: rgba(255,255,255,.5);
|
||||
--alert-tip-bg-color: rgba(255,255,255,.1);
|
||||
|
||||
--blockquote-border-color: rgba(255,255,255,.5);
|
||||
--blockquote-bg-color: rgba(255,255,255,.1);
|
||||
|
||||
--breadcrumb-bg-color: #2f3136;
|
||||
|
||||
/* Inline Code */
|
||||
|
||||
--ref-bg-color: black;
|
||||
--ref-color: #89d4f1;
|
||||
|
||||
/* Code Blocks */
|
||||
|
||||
--code-bg-color: #151515;
|
||||
--code-color: #d6deeb;
|
||||
--code-keyword-color: #569cd6;
|
||||
--code-comment-color: #57a64a;
|
||||
--code-macro-color: #beb7ff;
|
||||
--code-string-color: #d69d85;
|
||||
--code-string-escape-color: #ffd68f;
|
||||
--code-field-color: #c8c8c8;
|
||||
--code-function-color: #dcdcaa;
|
||||
--code-control-color: #d8a0df;
|
||||
--code-class-color: #4ec9b0;
|
||||
--code-number-color: #b5cea8;
|
||||
--code-params-color: #9a9a9a;
|
||||
--code-breakpoint-color: #8c2f2f;
|
||||
}
|
||||
|
||||
/* Code Block Overrides */
|
||||
|
||||
pre, legend {
|
||||
--scrollbar-thumb-bg-color: #333;
|
||||
}
|
||||
@ -1,681 +0,0 @@
|
||||
/* Discord Style */
|
||||
|
||||
::-webkit-scrollbar {
|
||||
width: 10px;
|
||||
}
|
||||
|
||||
::-webkit-scrollbar-track {
|
||||
background: var(--scrollbar-bg-color);
|
||||
}
|
||||
|
||||
::-webkit-scrollbar-thumb {
|
||||
background: var(--scrollbar-thumb-bg-color);
|
||||
border-color: var(--scrollbar-thumb-border-color);
|
||||
border-radius: 5px;
|
||||
}
|
||||
|
||||
::marker {
|
||||
unicode-bidi: isolate;
|
||||
font-variant-numeric: tabular-nums;
|
||||
text-transform: none;
|
||||
text-indent: 0px !important;
|
||||
text-align: start !important;
|
||||
text-align-last: start !important;
|
||||
}
|
||||
|
||||
*, :after, :before
|
||||
{
|
||||
-webkit-box-sizing: border-box;
|
||||
-moz-box-sizing: border-box;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
html, body
|
||||
{
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
font: 15px/150% 'Roboto', sans-serif;
|
||||
overflow: hidden;
|
||||
color: var(--text-color);
|
||||
background-color: var(--main-bg-color);
|
||||
|
||||
position: absolute;
|
||||
top: 0;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
}
|
||||
|
||||
img {
|
||||
max-width: 100%;
|
||||
}
|
||||
|
||||
ul > li, ol > li {
|
||||
display: list-item;
|
||||
}
|
||||
|
||||
h1,h2,h3,h4,h5
|
||||
{
|
||||
color: var(--link-active-color);
|
||||
position: relative;
|
||||
}
|
||||
|
||||
h1, h2
|
||||
{
|
||||
margin-block-start: 2em;
|
||||
}
|
||||
|
||||
h3
|
||||
{
|
||||
margin-block-start: 1em;
|
||||
font-weight: 300;
|
||||
font-size: 1.5em;
|
||||
color: var(--h3-color);
|
||||
margin-block-start: 3em;
|
||||
}
|
||||
|
||||
h4
|
||||
{
|
||||
opacity: 1;
|
||||
color: var(--h4-color);
|
||||
font-size: large;
|
||||
border-bottom: 2px solid var(--separator-color);
|
||||
margin: 20px 0 0 0;
|
||||
}
|
||||
|
||||
|
||||
h5 {
|
||||
margin-block-end: .8em;
|
||||
margin-block-start: 1em;
|
||||
font-size: .85em;
|
||||
font-weight: 500;
|
||||
color: var(--h5-color);
|
||||
}
|
||||
|
||||
h6 {
|
||||
font-size: .75em;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
p
|
||||
{
|
||||
font-weight: 400;
|
||||
}
|
||||
|
||||
ul
|
||||
{
|
||||
position: relative;
|
||||
}
|
||||
|
||||
ul, ol
|
||||
{
|
||||
padding-inline-start: 3em;
|
||||
}
|
||||
|
||||
ul.level1
|
||||
{
|
||||
list-style-type: none;
|
||||
padding-inline-start: 0;
|
||||
}
|
||||
|
||||
ul.level2, ul.level3
|
||||
{
|
||||
padding-inline-start: 1em;
|
||||
list-style-type: none;
|
||||
font-size: .9em;
|
||||
}
|
||||
|
||||
a
|
||||
{
|
||||
color: var(--link-color);
|
||||
text-decoration: none;
|
||||
transition: color .25s;
|
||||
}
|
||||
|
||||
a:focus, a:hover
|
||||
{
|
||||
color: var(--link-hover-color);
|
||||
text-decoration: underline;
|
||||
}
|
||||
|
||||
a.anchorjs-link:hover {
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
a.active, a:active
|
||||
{
|
||||
color: var(--link-active-color);
|
||||
}
|
||||
|
||||
.body-content
|
||||
{
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
height: 100%;
|
||||
overflow-x: hidden;
|
||||
overflow-y: hidden;
|
||||
}
|
||||
|
||||
.page-title
|
||||
{
|
||||
margin-block-start: 0;
|
||||
}
|
||||
|
||||
nav
|
||||
{
|
||||
width: 300px;
|
||||
transition: left .5s ease-out;
|
||||
position: fixed;
|
||||
left: -350px;
|
||||
top: 40px;
|
||||
bottom: 0;
|
||||
background-color: var(--sidebar-bg-color);
|
||||
overflow-y: auto;
|
||||
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
|
||||
z-index: 1000;
|
||||
}
|
||||
|
||||
h1:first-child
|
||||
{
|
||||
margin-block-start: 1.1em;
|
||||
margin-top: 1.1em;
|
||||
}
|
||||
|
||||
.sidebar
|
||||
{
|
||||
padding: 32px 17px 32px 32px;
|
||||
flex: 1;
|
||||
}
|
||||
|
||||
.sidebar-item
|
||||
{
|
||||
font-size: 1em;
|
||||
font-weight: 400;
|
||||
display: block;
|
||||
padding: 4px 16px;
|
||||
color: var(--sidebar-item-color);
|
||||
}
|
||||
|
||||
.sidebar-item.large, #navbar .sidebar-item
|
||||
{
|
||||
padding: 8px 16px;
|
||||
}
|
||||
|
||||
a.sidebar-item:hover, a.sidebar-item:focus
|
||||
{
|
||||
color: var(--link-active-color);
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
a.sidebar-item.active
|
||||
{
|
||||
color: var(--link-active-color);
|
||||
}
|
||||
|
||||
ul.level1 > li > a.sidebar-item
|
||||
{
|
||||
background-color: transparent;
|
||||
border-radius: 4px;
|
||||
}
|
||||
|
||||
#toc ul.level1 > li > a.sidebar-item.active
|
||||
{
|
||||
background-color: var(--link-active-bg-color);
|
||||
}
|
||||
|
||||
.sidebar-item-separator
|
||||
{
|
||||
height: 2px;
|
||||
width: 100%;
|
||||
background-color: var(--separator-color);
|
||||
margin: 2em 0;
|
||||
opacity: .8;
|
||||
}
|
||||
|
||||
span.sidebar-item
|
||||
{
|
||||
font-weight: 700;
|
||||
text-transform: uppercase;
|
||||
font-size: .8em;
|
||||
color: var(--text-color);
|
||||
margin-block-start: 1.25em;
|
||||
}
|
||||
|
||||
.main-panel
|
||||
{
|
||||
background-color: var(--main-bg-color);
|
||||
flex: 1;
|
||||
overflow-y: auto;
|
||||
padding: 20px 40px;
|
||||
}
|
||||
|
||||
.top-navbar
|
||||
{
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
align-items: center;
|
||||
padding: 0 40px;
|
||||
height: 40px;
|
||||
background-color: var(--topbar-bg-color);
|
||||
}
|
||||
|
||||
.burger-icon
|
||||
{
|
||||
margin-right: 1em;
|
||||
color: var(--button-color);
|
||||
}
|
||||
|
||||
.burger-icon:hover, .burger-icon:focus
|
||||
{
|
||||
color: var(--link-active-color);
|
||||
}
|
||||
|
||||
.burger-icon.active, .burger-icon:active
|
||||
{
|
||||
color: var(--link-active-color);
|
||||
}
|
||||
|
||||
.brand
|
||||
{
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: start;
|
||||
}
|
||||
|
||||
.logomark
|
||||
{
|
||||
height: 28px;
|
||||
}
|
||||
|
||||
.brand-title
|
||||
{
|
||||
padding: 0 .5em;
|
||||
font-size: .9em;
|
||||
color: var(--link-active-color);
|
||||
}
|
||||
|
||||
.footer
|
||||
{
|
||||
background-color: var(--footer-bg-color);
|
||||
padding: 20px;
|
||||
margin: 0 20px 20px 20px;
|
||||
border-radius: 8px;
|
||||
color: var(--link-active-color);
|
||||
}
|
||||
|
||||
.footer > h4
|
||||
{
|
||||
margin-block-start: 0;
|
||||
}
|
||||
|
||||
.blackout
|
||||
{
|
||||
display: block;
|
||||
visibility: hidden;
|
||||
position: absolute;
|
||||
z-index: 100;
|
||||
top: 40px;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
background-color: var(--footer-bg-color);
|
||||
}
|
||||
|
||||
@keyframes showThat {
|
||||
0% { opacity: 0; visibility: hidden; }
|
||||
1% { opacity: 0; visibility: visible; }
|
||||
100% { opacity: 1; visibility: visible;}
|
||||
}
|
||||
|
||||
@keyframes hideThat {
|
||||
0% { opacity: 1; visibility: visible; }
|
||||
99% { opacity: 0; visibility: visible; }
|
||||
100% { opacity: 0; visibility: hidden;}
|
||||
}
|
||||
|
||||
.showThat
|
||||
{
|
||||
animation: showThat .5s forwards;
|
||||
}
|
||||
|
||||
.hideThat
|
||||
{
|
||||
animation: hideThat .5s forwards;
|
||||
}
|
||||
|
||||
|
||||
|
||||
@media (min-width: 1024px)
|
||||
{
|
||||
nav
|
||||
{
|
||||
position: relative;
|
||||
left: 0!important;
|
||||
top: 0;
|
||||
bottom: 0;
|
||||
}
|
||||
|
||||
.top-navbar
|
||||
{
|
||||
display: none;
|
||||
}
|
||||
|
||||
.blackout
|
||||
{
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
|
||||
/* Table */
|
||||
|
||||
.table-responsive
|
||||
{
|
||||
overflow-x: auto;
|
||||
margin-bottom: 64px;
|
||||
}
|
||||
|
||||
table
|
||||
{
|
||||
background-color: var(--code-bg-color);
|
||||
border-collapse: collapse;
|
||||
width: 100%;
|
||||
table-layout: auto;
|
||||
}
|
||||
|
||||
table.table-striped tbody tr:nth-child(2n)
|
||||
{
|
||||
background-color: var(--table-strip-bg-color);
|
||||
}
|
||||
|
||||
table thead
|
||||
{
|
||||
background: var(--table-header-bg-color);
|
||||
}
|
||||
|
||||
table th
|
||||
{
|
||||
color: var(--table-header-color);
|
||||
text-transform: uppercase;
|
||||
font-size: 12px;
|
||||
line-height: 15px;
|
||||
border-bottom: 1px solid var(--table-header-border-color);
|
||||
padding: 8px;
|
||||
}
|
||||
|
||||
.table-condensed th {
|
||||
text-align: left;
|
||||
}
|
||||
|
||||
table td
|
||||
{
|
||||
padding: 8px;
|
||||
font-weight: 300;
|
||||
}
|
||||
|
||||
table td > p
|
||||
{
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
/* Alerts */
|
||||
.alert {
|
||||
border-radius: 4px;
|
||||
padding: 8px;
|
||||
margin: 25px 0;
|
||||
}
|
||||
|
||||
.alert > h5
|
||||
{
|
||||
display: none;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.alert > p
|
||||
{
|
||||
margin: 0;
|
||||
font-weight: 300;
|
||||
font-size: 13px;
|
||||
}
|
||||
|
||||
.alert.alert-info
|
||||
{
|
||||
border: 2px solid var(--alert-info-border-color);
|
||||
background: var(--alert-info-bg-color);
|
||||
}
|
||||
|
||||
.alert.alert-warning
|
||||
{
|
||||
border: 2px solid var(--alert-warning-border-color);
|
||||
background: var(--alert-warning-bg-color);
|
||||
}
|
||||
|
||||
.alert.alert-danger
|
||||
{
|
||||
border: 2px solid var(--alert-danger-border-color);
|
||||
background: var(--alert-danger-bg-color);
|
||||
}
|
||||
|
||||
.TIP.alert.alert-info
|
||||
{
|
||||
border: 2px solid var(--alert-tip-border-color);
|
||||
background: var(--alert-tip-bg-color);
|
||||
}
|
||||
|
||||
blockquote {
|
||||
margin: 8px 0;
|
||||
border-left: 4px solid var(--blockquote-border-color);
|
||||
padding: 8px;
|
||||
background: var(--blockquote-bg-color);
|
||||
border-radius: 4px;
|
||||
}
|
||||
|
||||
blockquote > p {
|
||||
margin: 0;
|
||||
font-style: italic;
|
||||
font-size: 13px;
|
||||
}
|
||||
|
||||
|
||||
/* Breadcrumb */
|
||||
|
||||
#breadcrumb
|
||||
{
|
||||
padding: 8px 16px;
|
||||
background: var(--breadcrumb-bg-color);
|
||||
border-radius: 4px;
|
||||
margin-bottom: 30px;
|
||||
}
|
||||
|
||||
#breadcrumb:empty
|
||||
{
|
||||
display: none;
|
||||
}
|
||||
|
||||
ul.breadcrumb
|
||||
{
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
ul.breadcrumb > li {
|
||||
margin-right: 6px;
|
||||
}
|
||||
|
||||
ul.breadcrumb > li::before
|
||||
{
|
||||
content: "/";
|
||||
margin-right: 5px;
|
||||
}
|
||||
|
||||
ul.breadcrumb > li:first-child::before
|
||||
{
|
||||
content: "";
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
|
||||
/* Code */
|
||||
|
||||
legend, pre
|
||||
{
|
||||
display: block;
|
||||
background-color: var(--code-bg-color);
|
||||
padding: 16px;
|
||||
border-radius: 4px;
|
||||
}
|
||||
|
||||
code
|
||||
{
|
||||
background-color: var(--code-bg-color);
|
||||
padding: 2px 4px;
|
||||
border-radius: 4px;
|
||||
}
|
||||
|
||||
.hljs
|
||||
{
|
||||
background: transparent;
|
||||
}
|
||||
|
||||
/* DocFX related */
|
||||
|
||||
.small {
|
||||
font-size: .9em;
|
||||
}
|
||||
|
||||
.pull-right
|
||||
{
|
||||
float: right;
|
||||
}
|
||||
|
||||
.hide
|
||||
{
|
||||
display: none;
|
||||
}
|
||||
|
||||
@media (max-width: 1023.98px)
|
||||
{
|
||||
.mobile-hide
|
||||
{
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
|
||||
li
|
||||
{
|
||||
display: block;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.expand-stub
|
||||
{
|
||||
cursor: pointer;
|
||||
position: absolute;
|
||||
width: 20px;
|
||||
height: 20px;
|
||||
left: -10px;
|
||||
}
|
||||
|
||||
ul.level1 > li > .expand-stub
|
||||
{
|
||||
display: none;
|
||||
}
|
||||
|
||||
.toc .nav > li > .expand-stub::before, .toc .nav > li.active > .expand-stub::before
|
||||
{
|
||||
content: " ";
|
||||
position: absolute;
|
||||
transform: rotate(-90deg);
|
||||
width: 10px;
|
||||
height: 10px;
|
||||
top: 5px;
|
||||
left: 5px;
|
||||
background-repeat: no-repeat;
|
||||
background: url(down-arrow.svg);
|
||||
}
|
||||
|
||||
.toc .nav > li.active > .expand-stub::before, .toc .nav > li.in > .expand-stub::before, .toc .nav > li.in.active > .expand-stub::before, .toc .nav > li.filtered > .expand-stub::before
|
||||
{
|
||||
transform: none;
|
||||
}
|
||||
|
||||
li > ul
|
||||
{
|
||||
display: none;
|
||||
}
|
||||
|
||||
li.in > ul
|
||||
{
|
||||
display: block;
|
||||
}
|
||||
|
||||
ul.level2 > li > a.sidebar-item,
|
||||
ul.level3 > li > a.sidebar-item
|
||||
{
|
||||
font-weight: 500;
|
||||
font-size: .95em;
|
||||
padding: 0;
|
||||
margin: 2px 16px;
|
||||
}
|
||||
|
||||
ul.level2 > li > a.sidebar-item
|
||||
{
|
||||
color: var(--sidebar-item-2nd-color);
|
||||
}
|
||||
|
||||
ul.level3 > li > a.sidebar-item
|
||||
{
|
||||
color: var(--sidebar-item-3rd-color);
|
||||
}
|
||||
|
||||
ul.level2 > li > a.sidebar-item:hover,
|
||||
ul.level2 > li > a.sidebar-item:focus,
|
||||
ul.level3 > li > a.sidebar-item:hover,
|
||||
ul.level3 > li > a.sidebar-item:focus
|
||||
{
|
||||
color: var(--link-active-color);
|
||||
text-decoration: underline;
|
||||
}
|
||||
|
||||
ul.level2 > li > a.sidebar-item.active,
|
||||
ul.level3 > li > a.sidebar-item.active
|
||||
{
|
||||
color: var(--link-active-color);
|
||||
}
|
||||
|
||||
.inheritance .level0:before,
|
||||
.inheritance .level1:before,
|
||||
.inheritance .level2:before,
|
||||
.inheritance .level3:before,
|
||||
.inheritance .level4:before,
|
||||
.inheritance .level5:before {
|
||||
content: '↳';
|
||||
margin-right: 5px;
|
||||
}
|
||||
|
||||
.inheritance .level0 {
|
||||
margin-left: 0em;
|
||||
}
|
||||
|
||||
.inheritance .level1 {
|
||||
margin-left: 1em;
|
||||
}
|
||||
|
||||
.inheritance .level2 {
|
||||
margin-left: 2em;
|
||||
}
|
||||
|
||||
.inheritance .level3 {
|
||||
margin-left: 3em;
|
||||
}
|
||||
|
||||
.inheritance .level4 {
|
||||
margin-left: 4em;
|
||||
}
|
||||
|
||||
.inheritance .level5 {
|
||||
margin-left: 5em;
|
||||
}
|
||||
@ -1,44 +0,0 @@
|
||||
<?xml version="1.0" encoding="iso-8859-1"?>
|
||||
<!-- Generator: Adobe Illustrator 19.0.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
|
||||
<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
|
||||
viewBox="0 0 491.996 491.996" style="enable-background:new 0 0 491.996 491.996;" xml:space="preserve">
|
||||
<g>
|
||||
<g color="white">
|
||||
<path d="M484.132,124.986l-16.116-16.228c-5.072-5.068-11.82-7.86-19.032-7.86c-7.208,0-13.964,2.792-19.036,7.86l-183.84,183.848
|
||||
L62.056,108.554c-5.064-5.068-11.82-7.856-19.028-7.856s-13.968,2.788-19.036,7.856l-16.12,16.128
|
||||
c-10.496,10.488-10.496,27.572,0,38.06l219.136,219.924c5.064,5.064,11.812,8.632,19.084,8.632h0.084
|
||||
c7.212,0,13.96-3.572,19.024-8.632l218.932-219.328c5.072-5.064,7.856-12.016,7.864-19.224
|
||||
C491.996,136.902,489.204,130.046,484.132,124.986z" fill="currentcolor"/>
|
||||
</g>
|
||||
</g>
|
||||
<g>
|
||||
</g>
|
||||
<g>
|
||||
</g>
|
||||
<g>
|
||||
</g>
|
||||
<g>
|
||||
</g>
|
||||
<g>
|
||||
</g>
|
||||
<g>
|
||||
</g>
|
||||
<g>
|
||||
</g>
|
||||
<g>
|
||||
</g>
|
||||
<g>
|
||||
</g>
|
||||
<g>
|
||||
</g>
|
||||
<g>
|
||||
</g>
|
||||
<g>
|
||||
</g>
|
||||
<g>
|
||||
</g>
|
||||
<g>
|
||||
</g>
|
||||
<g>
|
||||
</g>
|
||||
</svg>
|
||||
|
Before Width: | Height: | Size: 1.0 KiB |
@ -1,317 +0,0 @@
|
||||
/*!
|
||||
* jQuery pagination plugin v1.4.1
|
||||
* http://esimakin.github.io/twbs-pagination/
|
||||
*
|
||||
* Copyright 2014-2016, Eugene Simakin
|
||||
* Released under Apache 2.0 license
|
||||
* http://apache.org/licenses/LICENSE-2.0.html
|
||||
*/
|
||||
(function ($, window, document, undefined) {
|
||||
|
||||
'use strict';
|
||||
|
||||
var old = $.fn.twbsPagination;
|
||||
|
||||
// PROTOTYPE AND CONSTRUCTOR
|
||||
|
||||
var TwbsPagination = function (element, options) {
|
||||
this.$element = $(element);
|
||||
this.options = $.extend({}, $.fn.twbsPagination.defaults, options);
|
||||
|
||||
if (this.options.startPage < 1 || this.options.startPage > this.options.totalPages) {
|
||||
throw new Error('Start page option is incorrect');
|
||||
}
|
||||
|
||||
this.options.totalPages = parseInt(this.options.totalPages);
|
||||
if (isNaN(this.options.totalPages)) {
|
||||
throw new Error('Total pages option is not correct!');
|
||||
}
|
||||
|
||||
this.options.visiblePages = parseInt(this.options.visiblePages);
|
||||
if (isNaN(this.options.visiblePages)) {
|
||||
throw new Error('Visible pages option is not correct!');
|
||||
}
|
||||
|
||||
if (this.options.onPageClick instanceof Function) {
|
||||
this.$element.first().on('page', this.options.onPageClick);
|
||||
}
|
||||
|
||||
// hide if only one page exists
|
||||
if (this.options.hideOnlyOnePage && this.options.totalPages == 1) {
|
||||
this.$element.trigger('page', 1);
|
||||
return this;
|
||||
}
|
||||
|
||||
if (this.options.totalPages < this.options.visiblePages) {
|
||||
this.options.visiblePages = this.options.totalPages;
|
||||
}
|
||||
|
||||
if (this.options.href) {
|
||||
this.options.startPage = this.getPageFromQueryString();
|
||||
if (!this.options.startPage) {
|
||||
this.options.startPage = 1;
|
||||
}
|
||||
}
|
||||
|
||||
var tagName = (typeof this.$element.prop === 'function') ?
|
||||
this.$element.prop('tagName') : this.$element.attr('tagName');
|
||||
|
||||
if (tagName === 'UL') {
|
||||
this.$listContainer = this.$element;
|
||||
} else {
|
||||
this.$listContainer = $('<ul></ul>');
|
||||
}
|
||||
|
||||
this.$listContainer.addClass(this.options.paginationClass);
|
||||
|
||||
if (tagName !== 'UL') {
|
||||
this.$element.append(this.$listContainer);
|
||||
}
|
||||
|
||||
if (this.options.initiateStartPageClick) {
|
||||
this.show(this.options.startPage);
|
||||
} else {
|
||||
this.render(this.getPages(this.options.startPage));
|
||||
this.setupEvents();
|
||||
}
|
||||
|
||||
return this;
|
||||
};
|
||||
|
||||
TwbsPagination.prototype = {
|
||||
|
||||
constructor: TwbsPagination,
|
||||
|
||||
destroy: function () {
|
||||
this.$element.empty();
|
||||
this.$element.removeData('twbs-pagination');
|
||||
this.$element.off('page');
|
||||
|
||||
return this;
|
||||
},
|
||||
|
||||
show: function (page) {
|
||||
if (page < 1 || page > this.options.totalPages) {
|
||||
throw new Error('Page is incorrect.');
|
||||
}
|
||||
this.currentPage = page;
|
||||
|
||||
this.render(this.getPages(page));
|
||||
this.setupEvents();
|
||||
|
||||
this.$element.trigger('page', page);
|
||||
|
||||
return this;
|
||||
},
|
||||
|
||||
buildListItems: function (pages) {
|
||||
var listItems = [];
|
||||
|
||||
if (this.options.first) {
|
||||
listItems.push(this.buildItem('first', 1));
|
||||
}
|
||||
|
||||
if (this.options.prev) {
|
||||
var prev = pages.currentPage > 1 ? pages.currentPage - 1 : this.options.loop ? this.options.totalPages : 1;
|
||||
listItems.push(this.buildItem('prev', prev));
|
||||
}
|
||||
|
||||
for (var i = 0; i < pages.numeric.length; i++) {
|
||||
listItems.push(this.buildItem('page', pages.numeric[i]));
|
||||
}
|
||||
|
||||
if (this.options.next) {
|
||||
var next = pages.currentPage < this.options.totalPages ? pages.currentPage + 1 : this.options.loop ? 1 : this.options.totalPages;
|
||||
listItems.push(this.buildItem('next', next));
|
||||
}
|
||||
|
||||
if (this.options.last) {
|
||||
listItems.push(this.buildItem('last', this.options.totalPages));
|
||||
}
|
||||
|
||||
return listItems;
|
||||
},
|
||||
|
||||
buildItem: function (type, page) {
|
||||
var $itemContainer = $('<li></li>'),
|
||||
$itemContent = $('<a></a>'),
|
||||
itemText = this.options[type] ? this.makeText(this.options[type], page) : page;
|
||||
|
||||
$itemContainer.addClass(this.options[type + 'Class']);
|
||||
$itemContainer.data('page', page);
|
||||
$itemContainer.data('page-type', type);
|
||||
$itemContainer.append($itemContent.attr('href', this.makeHref(page)).addClass(this.options.anchorClass).html(itemText));
|
||||
|
||||
return $itemContainer;
|
||||
},
|
||||
|
||||
getPages: function (currentPage) {
|
||||
var pages = [];
|
||||
|
||||
var half = Math.floor(this.options.visiblePages / 2);
|
||||
var start = currentPage - half + 1 - this.options.visiblePages % 2;
|
||||
var end = currentPage + half;
|
||||
|
||||
// handle boundary case
|
||||
if (start <= 0) {
|
||||
start = 1;
|
||||
end = this.options.visiblePages;
|
||||
}
|
||||
if (end > this.options.totalPages) {
|
||||
start = this.options.totalPages - this.options.visiblePages + 1;
|
||||
end = this.options.totalPages;
|
||||
}
|
||||
|
||||
var itPage = start;
|
||||
while (itPage <= end) {
|
||||
pages.push(itPage);
|
||||
itPage++;
|
||||
}
|
||||
|
||||
return {"currentPage": currentPage, "numeric": pages};
|
||||
},
|
||||
|
||||
render: function (pages) {
|
||||
var _this = this;
|
||||
this.$listContainer.children().remove();
|
||||
var items = this.buildListItems(pages);
|
||||
jQuery.each(items, function(key, item){
|
||||
_this.$listContainer.append(item);
|
||||
});
|
||||
|
||||
this.$listContainer.children().each(function () {
|
||||
var $this = $(this),
|
||||
pageType = $this.data('page-type');
|
||||
|
||||
switch (pageType) {
|
||||
case 'page':
|
||||
if ($this.data('page') === pages.currentPage) {
|
||||
$this.addClass(_this.options.activeClass);
|
||||
}
|
||||
break;
|
||||
case 'first':
|
||||
$this.toggleClass(_this.options.disabledClass, pages.currentPage === 1);
|
||||
break;
|
||||
case 'last':
|
||||
$this.toggleClass(_this.options.disabledClass, pages.currentPage === _this.options.totalPages);
|
||||
break;
|
||||
case 'prev':
|
||||
$this.toggleClass(_this.options.disabledClass, !_this.options.loop && pages.currentPage === 1);
|
||||
break;
|
||||
case 'next':
|
||||
$this.toggleClass(_this.options.disabledClass,
|
||||
!_this.options.loop && pages.currentPage === _this.options.totalPages);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
});
|
||||
},
|
||||
|
||||
setupEvents: function () {
|
||||
var _this = this;
|
||||
this.$listContainer.off('click').on('click', 'li', function (evt) {
|
||||
var $this = $(this);
|
||||
if ($this.hasClass(_this.options.disabledClass) || $this.hasClass(_this.options.activeClass)) {
|
||||
return false;
|
||||
}
|
||||
// Prevent click event if href is not set.
|
||||
!_this.options.href && evt.preventDefault();
|
||||
_this.show(parseInt($this.data('page')));
|
||||
});
|
||||
},
|
||||
|
||||
makeHref: function (page) {
|
||||
return this.options.href ? this.generateQueryString(page) : "#";
|
||||
},
|
||||
|
||||
makeText: function (text, page) {
|
||||
return text.replace(this.options.pageVariable, page)
|
||||
.replace(this.options.totalPagesVariable, this.options.totalPages)
|
||||
},
|
||||
getPageFromQueryString: function (searchStr) {
|
||||
var search = this.getSearchString(searchStr),
|
||||
regex = new RegExp(this.options.pageVariable + '(=([^&#]*)|&|#|$)'),
|
||||
page = regex.exec(search);
|
||||
if (!page || !page[2]) {
|
||||
return null;
|
||||
}
|
||||
page = decodeURIComponent(page[2]);
|
||||
page = parseInt(page);
|
||||
if (isNaN(page)) {
|
||||
return null;
|
||||
}
|
||||
return page;
|
||||
},
|
||||
generateQueryString: function (pageNumber, searchStr) {
|
||||
var search = this.getSearchString(searchStr),
|
||||
regex = new RegExp(this.options.pageVariable + '=*[^&#]*');
|
||||
if (!search) return '';
|
||||
return '?' + search.replace(regex, this.options.pageVariable + '=' + pageNumber);
|
||||
|
||||
},
|
||||
getSearchString: function (searchStr) {
|
||||
var search = searchStr || window.location.search;
|
||||
if (search === '') {
|
||||
return null;
|
||||
}
|
||||
if (search.indexOf('?') === 0) search = search.substr(1);
|
||||
return search;
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
// PLUGIN DEFINITION
|
||||
|
||||
$.fn.twbsPagination = function (option) {
|
||||
var args = Array.prototype.slice.call(arguments, 1);
|
||||
var methodReturn;
|
||||
|
||||
var $this = $(this);
|
||||
var data = $this.data('twbs-pagination');
|
||||
var options = typeof option === 'object' ? option : {};
|
||||
|
||||
if (!data) $this.data('twbs-pagination', (data = new TwbsPagination(this, options) ));
|
||||
if (typeof option === 'string') methodReturn = data[ option ].apply(data, args);
|
||||
|
||||
return ( methodReturn === undefined ) ? $this : methodReturn;
|
||||
};
|
||||
|
||||
$.fn.twbsPagination.defaults = {
|
||||
totalPages: 1,
|
||||
startPage: 1,
|
||||
visiblePages: 5,
|
||||
initiateStartPageClick: true,
|
||||
hideOnlyOnePage: false,
|
||||
href: false,
|
||||
pageVariable: '{{page}}',
|
||||
totalPagesVariable: '{{total_pages}}',
|
||||
page: null,
|
||||
first: 'First',
|
||||
prev: 'Previous',
|
||||
next: 'Next',
|
||||
last: 'Last',
|
||||
loop: false,
|
||||
onPageClick: null,
|
||||
paginationClass: 'pagination',
|
||||
nextClass: 'page-item next',
|
||||
prevClass: 'page-item prev',
|
||||
lastClass: 'page-item last',
|
||||
firstClass: 'page-item first',
|
||||
pageClass: 'page-item',
|
||||
activeClass: 'active',
|
||||
disabledClass: 'disabled',
|
||||
anchorClass: 'page-link'
|
||||
};
|
||||
|
||||
$.fn.twbsPagination.Constructor = TwbsPagination;
|
||||
|
||||
$.fn.twbsPagination.noConflict = function () {
|
||||
$.fn.twbsPagination = old;
|
||||
return this;
|
||||
};
|
||||
|
||||
$.fn.twbsPagination.version = "1.4.1";
|
||||
|
||||
})(window.jQuery, window, document);
|
||||
@ -1,471 +0,0 @@
|
||||
body {
|
||||
font-size: var(--base-font-size);
|
||||
}
|
||||
|
||||
@media (max-width: 1024px) {
|
||||
body {
|
||||
font-size: var(--smalldevice-base-font-size);
|
||||
}
|
||||
}
|
||||
|
||||
/* Headings */
|
||||
|
||||
h1, h2, h3, h4, h5 {
|
||||
line-height: initial;
|
||||
}
|
||||
|
||||
h1, h1:first-child {
|
||||
font-size: 2.25em;
|
||||
letter-spacing: 0.5px;
|
||||
color: var(--h1-color);
|
||||
margin-block-start: 1em;
|
||||
margin-block-end: -0.05em;
|
||||
}
|
||||
|
||||
.article h1 {
|
||||
margin-block-end: -0.2em;
|
||||
}
|
||||
|
||||
h2 {
|
||||
font-size: 2.1em;
|
||||
color: var(--h2-color);
|
||||
}
|
||||
|
||||
.article h2 {
|
||||
margin-block-start: 1.3em;
|
||||
padding-bottom: 6px;
|
||||
border-bottom: 1px solid var(--separator-color);
|
||||
}
|
||||
|
||||
h3 {
|
||||
font-size: 1.95em;
|
||||
font-weight: 500;
|
||||
margin-block-start: 1.7em;
|
||||
}
|
||||
|
||||
.article h3 {
|
||||
font-size: 1.85em;
|
||||
font-weight: 500;
|
||||
margin-block-start: 1.2em;
|
||||
margin-block-end: 0.9em;
|
||||
}
|
||||
|
||||
h4 {
|
||||
font-size: 1.8em;
|
||||
font-weight: 400;
|
||||
margin-block-start: 2em;
|
||||
padding-bottom: 10px;
|
||||
}
|
||||
|
||||
.article h4 {
|
||||
font-size: 1.5em;
|
||||
font-weight: 300;
|
||||
margin-block-start: 1em;
|
||||
margin-block-end: 1em;
|
||||
padding-bottom: 0;
|
||||
border-bottom: none;
|
||||
}
|
||||
|
||||
h5 {
|
||||
font-size: 1.1em;
|
||||
}
|
||||
|
||||
.article h5 {
|
||||
font-size: 1.13em;
|
||||
font-weight: 400;
|
||||
text-decoration: underline;
|
||||
margin-block-start: 1.5em;
|
||||
margin-block-end: 1.0em;
|
||||
}
|
||||
|
||||
a.brand:hover
|
||||
{
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
a.brand .brand-title {
|
||||
font-size: 1.4em;
|
||||
font-weight: 500;
|
||||
letter-spacing: 0.5px;
|
||||
color: var(--appname-color);
|
||||
margin-top: 1px;
|
||||
padding: 0 0 0 0.4em;
|
||||
}
|
||||
|
||||
@media (min-width: 1024px) {
|
||||
a.brand .brand-title {
|
||||
font-size: 1.55em;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
a.brand .logomark {
|
||||
height: 35px;
|
||||
}
|
||||
|
||||
/* Top bar */
|
||||
|
||||
.top-navbar {
|
||||
height: 60px;
|
||||
padding: 0 0 0 10px;
|
||||
}
|
||||
|
||||
.burger-icon {
|
||||
margin-right: 10px;
|
||||
}
|
||||
|
||||
/* Side Bar */
|
||||
|
||||
.sidebar {
|
||||
padding: 25px 17px 32px 17px;
|
||||
}
|
||||
|
||||
.blackout {
|
||||
top: 60px;
|
||||
}
|
||||
|
||||
@media (max-width: 1023.98px) {
|
||||
.navbar-nav {
|
||||
margin-top: 0;
|
||||
}
|
||||
}
|
||||
|
||||
nav {
|
||||
width: 94%;
|
||||
max-width: var(--sidebar-width);
|
||||
left: calc(var(--sidebar-width) * -1);
|
||||
}
|
||||
|
||||
@media (max-width: 1023.98px) {
|
||||
nav {
|
||||
top: 60px;
|
||||
}
|
||||
}
|
||||
|
||||
nav ul {
|
||||
list-style-type: none;
|
||||
}
|
||||
|
||||
nav .nav a, nav .nav a:hover {
|
||||
text-decoration: none;
|
||||
cursor: pointer;
|
||||
display: block;
|
||||
}
|
||||
|
||||
nav a.sidebar-item {
|
||||
padding: 4px 0 4px 10px;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
nav a:focus, nav a.sidebar-item:hover, nav a.sidebar-item:focus {
|
||||
text-decoration: underline;
|
||||
}
|
||||
|
||||
nav a, nav a:hover, nav a:focus {
|
||||
color: var(--sidebar-item-color) !important;
|
||||
}
|
||||
|
||||
nav a.active, nav a.active:hover, nav a.active:focus {
|
||||
color: var(--sidebar-active-item-color) !important;
|
||||
}
|
||||
|
||||
.sidebar-item-separator {
|
||||
margin: 20px 0;
|
||||
}
|
||||
|
||||
#toc ul li a {
|
||||
padding: 0 0 0 10px;
|
||||
}
|
||||
|
||||
.search {
|
||||
background: var(--search-bg-color);
|
||||
border: 1px solid var(--search-border-color);
|
||||
border-radius: 5px;
|
||||
position: relative;
|
||||
margin-block-start: 25px;
|
||||
}
|
||||
|
||||
@media (max-width: 1023.98px) {
|
||||
.search {
|
||||
margin-block-start: 0;
|
||||
margin-block-end: 15px;
|
||||
}
|
||||
}
|
||||
|
||||
.search > input {
|
||||
font-size: 0.95em;
|
||||
color: var(--search-color);
|
||||
border: 0;
|
||||
background: none;
|
||||
padding: 11px 30px 10px 37px;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.search > input:focus {
|
||||
outline: 0;
|
||||
}
|
||||
|
||||
.search > .search-icon {
|
||||
font-size: 1.2em;
|
||||
color: var(--search-searchicon-color);
|
||||
position: absolute;
|
||||
top: 9px;
|
||||
left: 9px;
|
||||
}
|
||||
|
||||
.toc-filter {
|
||||
background: var(--toc-filter-bg-color);
|
||||
border: 1px solid var(--toc-filter-border-color);
|
||||
border-radius: 5px;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.toc-filter > input {
|
||||
font-size: 0.95em;
|
||||
color: var(--toc-filter-color);
|
||||
border: 0;
|
||||
background: none;
|
||||
padding: 11px 30px 10px 37px;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.toc-filter > input:focus {
|
||||
outline: 0;
|
||||
}
|
||||
|
||||
.toc-filter > .filter-icon {
|
||||
font-size: 1.2em;
|
||||
color: var(--toc-filter-filtericon-color);
|
||||
position: absolute;
|
||||
top: 9px;
|
||||
left: 9px;
|
||||
}
|
||||
|
||||
.toc-filter > .clear-icon {
|
||||
color: var(--toc-filter-clearicon-color);
|
||||
position: absolute;
|
||||
top: 9px;
|
||||
right: 9px;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.toc .nav > li > .expand-stub::before, .toc .nav > li.active > .expand-stub::before
|
||||
{
|
||||
width: 8px;
|
||||
height: 8px;
|
||||
top: 6px;
|
||||
left: 6px;
|
||||
}
|
||||
|
||||
#toc ul.level2
|
||||
{
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
|
||||
#toc ul.level1 > li > a {
|
||||
font-weight: 500;
|
||||
margin-bottom: 10px;
|
||||
padding: 5px 10px;
|
||||
}
|
||||
|
||||
#toc ul.level1 > li > a, #toc ul.level1 > li > a.active {
|
||||
background-color: var(--sidebar-level1-item-bg-color) !important;
|
||||
border-radius: 2px;
|
||||
}
|
||||
|
||||
#toc ul.level1 > li > a:hover, #toc ul.level1 > li > a.active:hover,
|
||||
#toc ul.level1 > li > a:focus, #toc ul.level1 > li > a.active:focus {
|
||||
background-color: var(--sidebar-level1-item-hover-bg-color) !important;
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
ul.level2 {
|
||||
padding-inline-start: 0.7em;
|
||||
}
|
||||
|
||||
ul.level2 .expand-stub {
|
||||
top: 1px;
|
||||
}
|
||||
|
||||
ul.level2 > li > a, ul.level2 > li > a.sidebar-item {
|
||||
font-weight: 400;
|
||||
color: var(--sidebar-item-color);
|
||||
margin: 4px 0 4px;
|
||||
}
|
||||
|
||||
ul.level3 {
|
||||
padding-inline-start: 1em;
|
||||
}
|
||||
|
||||
ul.level3 > li > a, ul.level3 > li > a.sidebar-item {
|
||||
font-size: 1.05em;
|
||||
color: var(--sidebar-item-color);
|
||||
margin: 4px 0;
|
||||
}
|
||||
|
||||
ul.level4 {
|
||||
padding-inline-start: 0;
|
||||
margin-bottom: 12px;
|
||||
}
|
||||
|
||||
ul.level4 > li > a, ul.level4 > li > a.sidebar-item {
|
||||
font-size: 1.05em;
|
||||
color: var(--sidebar-item-color);
|
||||
margin: 5px 0 5px 10px;
|
||||
}
|
||||
|
||||
/* Breadcrumbs */
|
||||
|
||||
.subnav.navbar {
|
||||
margin: 0 -15px;
|
||||
}
|
||||
|
||||
#breadcrumb {
|
||||
overflow: scroll;
|
||||
margin-bottom: 0;
|
||||
}
|
||||
|
||||
#breadcrumb::-webkit-scrollbar {
|
||||
display: none;
|
||||
}
|
||||
|
||||
#breadcrumb a {
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
#breadcrumb wbr {
|
||||
display: none;
|
||||
}
|
||||
|
||||
/* Search Results */
|
||||
|
||||
#search-results h1 {
|
||||
margin-block-start: 0.5em;
|
||||
}
|
||||
|
||||
#search-results .item-title {
|
||||
font-size: 1.3em;
|
||||
margin-top: 1.5em;
|
||||
}
|
||||
|
||||
#search-results .item-href {
|
||||
font-size: 0.85em;
|
||||
}
|
||||
|
||||
#search-results .item-brief {
|
||||
margin-top: 0.7em;
|
||||
}
|
||||
|
||||
#search-results ul.pagination {
|
||||
text-align: center;
|
||||
padding: 10px 0 0 0;
|
||||
margin-block-start: 40px;
|
||||
border-top: 1px solid var(--separator-color);
|
||||
}
|
||||
|
||||
#search-results ul.pagination > li {
|
||||
display: inline-block;
|
||||
margin: 0 10px;
|
||||
}
|
||||
|
||||
#search-results ul.pagination > li.disabled a, #search-results ul.pagination > li.disabled a:hover {
|
||||
color: var(--text-color);
|
||||
cursor: txt;
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
/* Content */
|
||||
|
||||
.main-panel {
|
||||
margin-bottom: 60px;
|
||||
padding: 20px;
|
||||
}
|
||||
|
||||
@media (min-width: 1024px) {
|
||||
.main-panel {
|
||||
margin-bottom: 0;
|
||||
padding: 20px 40px;
|
||||
}
|
||||
}
|
||||
|
||||
.pull-right {
|
||||
margin-top: 70px;
|
||||
/* Fix unclickable links */
|
||||
position: relative;
|
||||
z-index: 1;
|
||||
}
|
||||
|
||||
.divider {
|
||||
margin-left: 4px;
|
||||
}
|
||||
|
||||
article ul li, article ol li {
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
|
||||
legend, pre {
|
||||
padding: 6px;
|
||||
}
|
||||
|
||||
.hljs {
|
||||
color: var(--code-color);
|
||||
}
|
||||
|
||||
.hljs::-webkit-scrollbar {
|
||||
height: 6px;
|
||||
}
|
||||
|
||||
.hljs-keyword, .hljs-title, .hljs-built_in {
|
||||
font-style: normal;
|
||||
}
|
||||
|
||||
p .xref, code {
|
||||
background-color: var(--ref-bg-color);
|
||||
color: var(--ref-color);
|
||||
padding: 2px 3px;
|
||||
font-family: monospace;
|
||||
font-size: 0.95em;
|
||||
border-radius: 6px;
|
||||
}
|
||||
|
||||
span.parametername {
|
||||
font-family: monospace;
|
||||
}
|
||||
|
||||
.table {
|
||||
width: auto;
|
||||
}
|
||||
|
||||
.table-responsive {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
|
||||
table th {
|
||||
font-size: 14px;
|
||||
padding: 9px 10px;
|
||||
}
|
||||
|
||||
table td p {
|
||||
font-weight: 300;
|
||||
}
|
||||
|
||||
table td {
|
||||
padding: 6px 10px;
|
||||
}
|
||||
|
||||
.footer {
|
||||
text-align: center;
|
||||
color: var(--text-color);
|
||||
padding: 10px;
|
||||
}
|
||||
|
||||
.footer a:hover, .footer a:focus {
|
||||
text-decoration: underline;
|
||||
}
|
||||
|
||||
.copyright-footer {
|
||||
font-size: 0.85em;
|
||||
font-weight: bold;
|
||||
text-align: center;
|
||||
margin-block-start: 30px;
|
||||
}
|
||||
@ -1,38 +0,0 @@
|
||||
// Copyright (c) Microsoft. All rights reserved. Licensed under the MIT license. See LICENSE file in the project root for full license information.
|
||||
|
||||
function toggleMenu() {
|
||||
|
||||
var sidebar = document.getElementById("sidebar");
|
||||
var blackout = document.getElementById("blackout");
|
||||
|
||||
if (sidebar.style.left === "0px")
|
||||
{
|
||||
sidebar.style.left = "-" + sidebar.offsetWidth + "px";
|
||||
blackout.classList.remove("showThat");
|
||||
blackout.classList.add("hideThat");
|
||||
}
|
||||
else
|
||||
{
|
||||
sidebar.style.left = "0px";
|
||||
blackout.classList.remove("hideThat");
|
||||
blackout.classList.add("showThat");
|
||||
}
|
||||
}
|
||||
|
||||
$(function() {
|
||||
$('table').each(function(a, tbl) {
|
||||
var currentTableRows = $(tbl).find('tbody tr').length;
|
||||
$(tbl).find('th').each(function(i) {
|
||||
var remove = 0;
|
||||
var currentTable = $(this).parents('table');
|
||||
|
||||
var tds = currentTable.find('tr td:nth-child(' + (i + 1) + ')');
|
||||
tds.each(function(j) { if ($(this).text().trim() === '') remove++; });
|
||||
|
||||
if (remove == currentTableRows) {
|
||||
$(this).hide();
|
||||
tds.hide();
|
||||
}
|
||||
});
|
||||
});
|
||||
});
|
||||
@ -1 +0,0 @@
|
||||
/*! url - v1.8.6 - 2013-11-22 */window.url=function(){function a(a){return!isNaN(parseFloat(a))&&isFinite(a)}return function(b,c){var d=c||window.location.toString();if(!b)return d;b=b.toString(),"//"===d.substring(0,2)?d="http:"+d:1===d.split("://").length&&(d="http://"+d),c=d.split("/");var e={auth:""},f=c[2].split("@");1===f.length?f=f[0].split(":"):(e.auth=f[0],f=f[1].split(":")),e.protocol=c[0],e.hostname=f[0],e.port=f[1]||("https"===e.protocol.split(":")[0].toLowerCase()?"443":"80"),e.pathname=(c.length>3?"/":"")+c.slice(3,c.length).join("/").split("?")[0].split("#")[0];var g=e.pathname;"/"===g.charAt(g.length-1)&&(g=g.substring(0,g.length-1));var h=e.hostname,i=h.split("."),j=g.split("/");if("hostname"===b)return h;if("domain"===b)return/^(([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])\.){3}([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])$/.test(h)?h:i.slice(-2).join(".");if("sub"===b)return i.slice(0,i.length-2).join(".");if("port"===b)return e.port;if("protocol"===b)return e.protocol.split(":")[0];if("auth"===b)return e.auth;if("user"===b)return e.auth.split(":")[0];if("pass"===b)return e.auth.split(":")[1]||"";if("path"===b)return e.pathname;if("."===b.charAt(0)){if(b=b.substring(1),a(b))return b=parseInt(b,10),i[0>b?i.length+b:b-1]||""}else{if(a(b))return b=parseInt(b,10),j[0>b?j.length+b:b]||"";if("file"===b)return j.slice(-1)[0];if("filename"===b)return j.slice(-1)[0].split(".")[0];if("fileext"===b)return j.slice(-1)[0].split(".")[1]||"";if("?"===b.charAt(0)||"#"===b.charAt(0)){var k=d,l=null;if("?"===b.charAt(0)?k=(k.split("?")[1]||"").split("#")[0]:"#"===b.charAt(0)&&(k=k.split("#")[1]||""),!b.charAt(1))return k;b=b.substring(1),k=k.split("&");for(var m=0,n=k.length;n>m;m++)if(l=k[m].split("="),l[0]===b)return l[1]||"";return null}}return""}}(),"undefined"!=typeof jQuery&&jQuery.extend({url:function(a,b){return window.url(a,b)}});
|
||||
@ -1,22 +0,0 @@
|
||||
{{!Copyright (c) Microsoft. All rights reserved. Licensed under the MIT license. See LICENSE file in the project root for full license information.}}
|
||||
|
||||
<div id="sidetoggle">
|
||||
<div>
|
||||
{{^_disableSideFilter}}
|
||||
<div class="sidefilter">
|
||||
<form class="toc-filter">
|
||||
<i class="bi bi-funnel-fill filter-icon"></i>
|
||||
<i id="toc_filter_clear" class="bi bi-x-lg clear-icon"></i>
|
||||
<input type="text" id="toc_filter_input" placeholder="{{__global.tocFilter}}" autocomplete="off" onkeypress="if(event.keyCode==13) {return false;}">
|
||||
</form>
|
||||
</div>
|
||||
{{/_disableSideFilter}}
|
||||
<div class="sidetoc">
|
||||
<div class="toc" id="toc">
|
||||
{{^leaf}}
|
||||
{{>partials/li}}
|
||||
{{/leaf}}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@ -1,2 +1,2 @@
|
||||
- name: API Documentation
|
||||
href: api/
|
||||
- name: Plugin API
|
||||
href: api/
|
||||
1
docfx/docs/getting-started.md
Normal file
1
docfx/docs/getting-started.md
Normal file
@ -0,0 +1 @@
|
||||
# Getting Started
|
||||
1
docfx/docs/introduction.md
Normal file
1
docfx/docs/introduction.md
Normal file
@ -0,0 +1 @@
|
||||
# Introduction
|
||||
4
docfx/docs/toc.yml
Normal file
4
docfx/docs/toc.yml
Normal file
@ -0,0 +1,4 @@
|
||||
- name: Introduction
|
||||
href: introduction.md
|
||||
- name: Getting Started
|
||||
href: getting-started.md
|
||||
@ -1,10 +0,0 @@
|
||||
To generate the [Artemis API docs](https://artemis-rgb.com/docs/) we use [DocFX](https://dotnet.github.io/docfx/).
|
||||
|
||||
To build locally run the following commands from this folder.
|
||||
|
||||
#### Want to build? Follow these instructions (Windows)
|
||||
1. Ensure you can build the Artemis solution as per the [main build instructions](https://github.com/Artemis-RGB/Artemis#want-to-build-follow-these-instructions)
|
||||
2. Install DocFX (with Chocolatey: `choco install docfx`)
|
||||
3. Open PowerShell in `<repo>\docfx` (the same folder as this readme file)
|
||||
4. Run `docfx .\docfx_project\docfx.json` to build static files
|
||||
Run `docfx .\docfx_project\docfx.json --serve` to serve locally
|
||||
@ -1,6 +1,6 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net7.0</TargetFramework>
|
||||
<TargetFramework>net8.0</TargetFramework>
|
||||
<PreserveCompilationContext>false</PreserveCompilationContext>
|
||||
<ShouldIncludeNativeSkiaSharp>false</ShouldIncludeNativeSkiaSharp>
|
||||
<AssemblyTitle>Artemis.Core</AssemblyTitle>
|
||||
@ -36,20 +36,20 @@
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="DryIoc.dll" Version="5.4.3" />
|
||||
<PackageReference Include="EmbedIO" Version="3.5.2" />
|
||||
<PackageReference Include="HidSharp" Version="2.1.0" />
|
||||
<PackageReference Include="Humanizer.Core" Version="2.14.1" />
|
||||
<PackageReference Include="JetBrains.Annotations" Version="2023.3.0" />
|
||||
<PackageReference Include="McMaster.NETCore.Plugins" Version="1.4.0" />
|
||||
<PackageReference Include="Newtonsoft.Json" Version="13.0.3" />
|
||||
<PackageReference Include="RGB.NET.Core" Version="2.0.4-prerelease.1" />
|
||||
<PackageReference Include="RGB.NET.Layout" Version="2.0.4-prerelease.1" />
|
||||
<PackageReference Include="RGB.NET.Presets" Version="2.0.4-prerelease.1" />
|
||||
<PackageReference Include="Serilog.Sinks.Console" Version="5.0.1" />
|
||||
<PackageReference Include="Serilog.Sinks.Debug" Version="2.0.0" />
|
||||
<PackageReference Include="Serilog.Sinks.File" Version="5.0.0" />
|
||||
<PackageReference Include="SkiaSharp" Version="2.88.7" />
|
||||
<PackageReference Include="DryIoc.dll" />
|
||||
<PackageReference Include="EmbedIO" />
|
||||
<PackageReference Include="HidSharp" />
|
||||
<PackageReference Include="Humanizer.Core" />
|
||||
<PackageReference Include="JetBrains.Annotations" />
|
||||
<PackageReference Include="McMaster.NETCore.Plugins" />
|
||||
<PackageReference Include="Newtonsoft.Json" />
|
||||
<PackageReference Include="RGB.NET.Core" />
|
||||
<PackageReference Include="RGB.NET.Layout" />
|
||||
<PackageReference Include="RGB.NET.Presets" />
|
||||
<PackageReference Include="Serilog.Sinks.Console" />
|
||||
<PackageReference Include="Serilog.Sinks.Debug" />
|
||||
<PackageReference Include="Serilog.Sinks.File" />
|
||||
<PackageReference Include="SkiaSharp" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
|
||||
@ -5,7 +5,7 @@ using Artemis.Core.DryIoc.Factories;
|
||||
using Artemis.Core.Providers;
|
||||
using Artemis.Core.Services;
|
||||
using Artemis.Storage;
|
||||
using Artemis.Storage.Migrations.Interfaces;
|
||||
using Artemis.Storage.Migrations;
|
||||
using Artemis.Storage.Repositories.Interfaces;
|
||||
using DryIoc;
|
||||
|
||||
@ -36,6 +36,7 @@ public static class ContainerExtensions
|
||||
|
||||
// Bind migrations
|
||||
container.RegisterMany(storageAssembly, type => type.IsAssignableTo<IStorageMigration>(), Reuse.Singleton, nonPublicServiceTypes: true);
|
||||
container.RegisterMany(storageAssembly, type => type.IsAssignableTo<IProfileMigration>(), Reuse.Singleton, nonPublicServiceTypes: true);
|
||||
|
||||
container.RegisterMany(coreAssembly, type => type.IsAssignableTo<ILayoutProvider>(), Reuse.Singleton);
|
||||
container.Register<IPluginSettingsFactory, PluginSettingsFactory>(Reuse.Singleton);
|
||||
|
||||
@ -248,8 +248,8 @@ public sealed class Layer : RenderProfileElement
|
||||
typeof(PropertyGroupDescriptionAttribute)
|
||||
)!;
|
||||
|
||||
LayerEntity.GeneralPropertyGroup ??= new PropertyGroupEntity {Identifier = generalAttribute.Identifier};
|
||||
LayerEntity.TransformPropertyGroup ??= new PropertyGroupEntity {Identifier = transformAttribute.Identifier};
|
||||
LayerEntity.GeneralPropertyGroup ??= new PropertyGroupEntity {Identifier = generalAttribute.Identifier!};
|
||||
LayerEntity.TransformPropertyGroup ??= new PropertyGroupEntity {Identifier = transformAttribute.Identifier!};
|
||||
|
||||
General.Initialize(this, null, generalAttribute, LayerEntity.GeneralPropertyGroup);
|
||||
Transform.Initialize(this, null, transformAttribute, LayerEntity.TransformPropertyGroup);
|
||||
|
||||
@ -240,7 +240,8 @@ public abstract class LayerPropertyGroup : IDisposable
|
||||
foreach (LayerPropertyGroup layerPropertyGroup in LayerPropertyGroups)
|
||||
{
|
||||
layerPropertyGroup.ApplyToEntity();
|
||||
PropertyGroupEntity.PropertyGroups.Add(layerPropertyGroup.PropertyGroupEntity);
|
||||
if (layerPropertyGroup.PropertyGroupEntity != null)
|
||||
PropertyGroupEntity.PropertyGroups.Add(layerPropertyGroup.PropertyGroupEntity);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -46,7 +46,7 @@ public class ArtemisDevice : CorePropertyChanged
|
||||
InputIdentifiers = new List<ArtemisDeviceInputIdentifier>();
|
||||
InputMappings = new Dictionary<ArtemisLed, ArtemisLed>();
|
||||
Categories = new HashSet<DeviceCategory>();
|
||||
LayoutSelection = new LayoutSelection {Type = DefaultLayoutProvider.LayoutType};
|
||||
LayoutSelection = new LayoutSelection {Type = DefaultLayoutProvider.LAYOUT_TYPE};
|
||||
|
||||
RgbDevice.ColorCorrections.Clear();
|
||||
RgbDevice.ColorCorrections.Add(new ScaleColorCorrection(this));
|
||||
@ -75,7 +75,7 @@ public class ArtemisDevice : CorePropertyChanged
|
||||
InputIdentifiers = new List<ArtemisDeviceInputIdentifier>();
|
||||
InputMappings = new Dictionary<ArtemisLed, ArtemisLed>();
|
||||
Categories = new HashSet<DeviceCategory>();
|
||||
LayoutSelection = new LayoutSelection {Type = DefaultLayoutProvider.LayoutType};
|
||||
LayoutSelection = new LayoutSelection {Type = DefaultLayoutProvider.LAYOUT_TYPE};
|
||||
|
||||
foreach (DeviceInputIdentifierEntity identifierEntity in DeviceEntity.InputIdentifiers)
|
||||
InputIdentifiers.Add(new ArtemisDeviceInputIdentifier(identifierEntity.InputProvider, identifierEntity.Identifier));
|
||||
@ -155,6 +155,9 @@ public class ArtemisDevice : CorePropertyChanged
|
||||
/// </summary>
|
||||
public HashSet<DeviceCategory> Categories { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the layout selection applied to this device
|
||||
/// </summary>
|
||||
public LayoutSelection LayoutSelection { get; }
|
||||
|
||||
/// <summary>
|
||||
|
||||
@ -57,6 +57,9 @@ public class ArtemisLayout
|
||||
/// </summary>
|
||||
public LayoutCustomDeviceData LayoutCustomDeviceData { get; private set; } = null!;
|
||||
|
||||
/// <summary>
|
||||
/// Gets a boolean indicating whether this layout is a default layout or not
|
||||
/// </summary>
|
||||
public bool IsDefaultLayout { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
|
||||
@ -65,7 +65,7 @@ public class LayerBrushDescriptor
|
||||
BaseLayerBrush brush = (BaseLayerBrush) Provider.Plugin.Resolve(LayerBrushType);
|
||||
brush.Layer = layer;
|
||||
brush.Descriptor = this;
|
||||
brush.LayerBrushEntity = entity ?? new LayerBrushEntity {ProviderId = Provider.Id, BrushType = LayerBrushType.FullName};
|
||||
brush.LayerBrushEntity = entity ?? new LayerBrushEntity {ProviderId = Provider.Id, BrushType = LayerBrushType.FullName ?? throw new InvalidOperationException()};
|
||||
|
||||
brush.Initialize();
|
||||
return brush;
|
||||
|
||||
@ -231,7 +231,7 @@ public abstract class BaseLayerEffect : BreakableModel, IDisposable, IStorageMod
|
||||
return;
|
||||
|
||||
LayerEffectEntity.ProviderId = Descriptor.Provider.Id;
|
||||
LayerEffectEntity.EffectType = GetType().FullName;
|
||||
LayerEffectEntity.EffectType = GetType().FullName ?? throw new InvalidOperationException();
|
||||
BaseProperties?.ApplyToEntity();
|
||||
LayerEffectEntity.PropertyGroup = BaseProperties?.PropertyGroupEntity;
|
||||
}
|
||||
|
||||
81
src/Artemis.Core/Plugins/Nodes/NodeProvider.cs
Normal file
81
src/Artemis.Core/Plugins/Nodes/NodeProvider.cs
Normal file
@ -0,0 +1,81 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.ObjectModel;
|
||||
using System.Reflection;
|
||||
using SkiaSharp;
|
||||
|
||||
namespace Artemis.Core.Nodes;
|
||||
|
||||
/// <summary>
|
||||
/// Allows you to register one or more <see cref="INode" />s usable by node scripts.
|
||||
/// </summary>
|
||||
public abstract class NodeProvider : PluginFeature
|
||||
{
|
||||
private readonly List<NodeData> _nodeDescriptors;
|
||||
|
||||
/// <summary>
|
||||
/// Creates a new instance of the <see cref="NodeProvider"/> class.
|
||||
/// </summary>
|
||||
public NodeProvider()
|
||||
{
|
||||
_nodeDescriptors = new List<NodeData>();
|
||||
NodeDescriptors = new ReadOnlyCollection<NodeData>(_nodeDescriptors);
|
||||
Disabled += OnDisabled;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// A read-only collection of all nodes added with <see cref="RegisterNodeType{T}" />
|
||||
/// </summary>
|
||||
public ReadOnlyCollection<NodeData> NodeDescriptors { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Adds a node descriptor for a given node, so that it appears in the UI.
|
||||
/// <para>Note: You do not need to manually remove these on disable</para>
|
||||
/// </summary>
|
||||
/// <typeparam name="T">The type of the node you wish to register</typeparam>
|
||||
protected void RegisterNodeType<T>() where T : INode
|
||||
{
|
||||
RegisterNodeType(typeof(T));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Adds a node descriptor for a given node, so that it appears in the UI.
|
||||
/// <para>Note: You do not need to manually remove these on disable</para>
|
||||
/// </summary>
|
||||
/// <param name="nodeType">The type of the node you wish to register</param>
|
||||
protected void RegisterNodeType(Type nodeType)
|
||||
{
|
||||
if (!IsEnabled)
|
||||
throw new ArtemisPluginFeatureException(this, "Can only add a node descriptor when the plugin is enabled");
|
||||
if (nodeType == null)
|
||||
throw new ArgumentNullException(nameof(nodeType));
|
||||
if (!nodeType.IsAssignableTo(typeof(INode)))
|
||||
throw new ArgumentException("Node has to be a base type of the Node-Type.", nameof(nodeType));
|
||||
|
||||
NodeAttribute? nodeAttribute = nodeType.GetCustomAttribute<NodeAttribute>();
|
||||
string name = nodeAttribute?.Name ?? nodeType.Name;
|
||||
string description = nodeAttribute?.Description ?? string.Empty;
|
||||
string category = nodeAttribute?.Category ?? string.Empty;
|
||||
string helpUrl = nodeAttribute?.HelpUrl ?? string.Empty;
|
||||
|
||||
NodeData nodeData = new(this, nodeType, name, description, category, helpUrl, nodeAttribute?.InputType, nodeAttribute?.OutputType);
|
||||
_nodeDescriptors.Add(nodeData);
|
||||
NodeTypeStore.Add(nodeData);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Adds a color for lines of the provided type.
|
||||
/// </summary>
|
||||
/// <param name="color">The color to add.</param>
|
||||
/// <typeparam name="T">The type to use the color for.</typeparam>
|
||||
protected TypeColorRegistration RegisterTypeColor<T>(SKColor color)
|
||||
{
|
||||
return NodeTypeStore.AddColor(typeof(T), color, this);
|
||||
}
|
||||
|
||||
private void OnDisabled(object? sender, EventArgs e)
|
||||
{
|
||||
// The store will clean up the registrations by itself, the plugin feature just needs to clear its own list
|
||||
_nodeDescriptors.Clear();
|
||||
}
|
||||
}
|
||||
@ -41,7 +41,7 @@ public class PluginSettings
|
||||
if (_settingEntities.ContainsKey(name))
|
||||
return (PluginSetting<T>) _settingEntities[name];
|
||||
// Try to find in database
|
||||
PluginSettingEntity settingEntity = _pluginRepository.GetSettingByNameAndGuid(name, Plugin.Guid);
|
||||
PluginSettingEntity? settingEntity = _pluginRepository.GetSettingByNameAndGuid(name, Plugin.Guid);
|
||||
// If not found, create a new one
|
||||
if (settingEntity == null)
|
||||
{
|
||||
|
||||
@ -1,8 +1,14 @@
|
||||
namespace Artemis.Core.Providers;
|
||||
|
||||
/// <summary>
|
||||
/// Represents a layout provider that loads a layout from a custom path.
|
||||
/// </summary>
|
||||
public class CustomPathLayoutProvider : ILayoutProvider
|
||||
{
|
||||
public static string LayoutType = "CustomPath";
|
||||
/// <summary>
|
||||
/// The layout type of this layout provider.
|
||||
/// </summary>
|
||||
public const string LAYOUT_TYPE = "CustomPath";
|
||||
|
||||
/// <inheritdoc />
|
||||
public ArtemisLayout? GetDeviceLayout(ArtemisDevice device)
|
||||
@ -21,7 +27,7 @@ public class CustomPathLayoutProvider : ILayoutProvider
|
||||
/// <inheritdoc />
|
||||
public bool IsMatch(ArtemisDevice device)
|
||||
{
|
||||
return device.LayoutSelection.Type == LayoutType;
|
||||
return device.LayoutSelection.Type == LAYOUT_TYPE;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@ -31,7 +37,7 @@ public class CustomPathLayoutProvider : ILayoutProvider
|
||||
/// <param name="path">The path to the custom layout.</param>
|
||||
public void ConfigureDevice(ArtemisDevice device, string? path)
|
||||
{
|
||||
device.LayoutSelection.Type = LayoutType;
|
||||
device.LayoutSelection.Type = LAYOUT_TYPE;
|
||||
device.LayoutSelection.Parameter = path;
|
||||
}
|
||||
}
|
||||
@ -1,8 +1,14 @@
|
||||
namespace Artemis.Core.Providers;
|
||||
|
||||
/// <summary>
|
||||
/// Represents a layout provider that loads a layout from the plugin and falls back to a default layout.
|
||||
/// </summary>
|
||||
public class DefaultLayoutProvider : ILayoutProvider
|
||||
{
|
||||
public static string LayoutType = "Default";
|
||||
/// <summary>
|
||||
/// The layout type of this layout provider.
|
||||
/// </summary>
|
||||
public const string LAYOUT_TYPE = "Default";
|
||||
|
||||
/// <inheritdoc />
|
||||
public ArtemisLayout? GetDeviceLayout(ArtemisDevice device)
|
||||
@ -26,7 +32,7 @@ public class DefaultLayoutProvider : ILayoutProvider
|
||||
/// <inheritdoc />
|
||||
public bool IsMatch(ArtemisDevice device)
|
||||
{
|
||||
return device.LayoutSelection.Type == LayoutType;
|
||||
return device.LayoutSelection.Type == LAYOUT_TYPE;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@ -35,7 +41,7 @@ public class DefaultLayoutProvider : ILayoutProvider
|
||||
/// <param name="device">The device to apply the provider to.</param>
|
||||
public void ConfigureDevice(ArtemisDevice device)
|
||||
{
|
||||
device.LayoutSelection.Type = LayoutType;
|
||||
device.LayoutSelection.Type = LAYOUT_TYPE;
|
||||
device.LayoutSelection.Parameter = null;
|
||||
}
|
||||
}
|
||||
@ -12,6 +12,17 @@ public interface ILayoutProvider
|
||||
/// <returns>The resulting layout if one was available; otherwise <see langword="null" />.</returns>
|
||||
ArtemisLayout? GetDeviceLayout(ArtemisDevice device);
|
||||
|
||||
/// <summary>
|
||||
/// Applies the layout to the provided device.
|
||||
/// </summary>
|
||||
/// <param name="device">The device to apply to.</param>
|
||||
/// <param name="layout">The layout to apply.</param>
|
||||
void ApplyLayout(ArtemisDevice device, ArtemisLayout layout);
|
||||
|
||||
/// <summary>
|
||||
/// Determines whether the provided device is configured to use this layout provider.
|
||||
/// </summary>
|
||||
/// <param name="device">The device to check.</param>
|
||||
/// <returns>A value indicating whether the provided device is configured to use this layout provider.</returns>
|
||||
bool IsMatch(ArtemisDevice device);
|
||||
}
|
||||
@ -1,8 +1,14 @@
|
||||
namespace Artemis.Core.Providers;
|
||||
|
||||
/// <summary>
|
||||
/// Represents a layout provider that does not load a layout.
|
||||
/// </summary>
|
||||
public class NoneLayoutProvider : ILayoutProvider
|
||||
{
|
||||
public static string LayoutType = "None";
|
||||
/// <summary>
|
||||
/// The layout type of this layout provider.
|
||||
/// </summary>
|
||||
public const string LAYOUT_TYPE = "None";
|
||||
|
||||
/// <inheritdoc />
|
||||
public ArtemisLayout? GetDeviceLayout(ArtemisDevice device)
|
||||
@ -19,7 +25,7 @@ public class NoneLayoutProvider : ILayoutProvider
|
||||
/// <inheritdoc />
|
||||
public bool IsMatch(ArtemisDevice device)
|
||||
{
|
||||
return device.LayoutSelection.Type == LayoutType;
|
||||
return device.LayoutSelection.Type == LAYOUT_TYPE;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@ -28,7 +34,7 @@ public class NoneLayoutProvider : ILayoutProvider
|
||||
/// <param name="device">The device to apply the provider to.</param>
|
||||
public void ConfigureDevice(ArtemisDevice device)
|
||||
{
|
||||
device.LayoutSelection.Type = LayoutType;
|
||||
device.LayoutSelection.Type = LAYOUT_TYPE;
|
||||
device.LayoutSelection.Parameter = null;
|
||||
}
|
||||
}
|
||||
@ -1,11 +1,9 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
using System.Security.Cryptography;
|
||||
using System.Text;
|
||||
using Artemis.Storage.Entities.Profile.Nodes;
|
||||
using DryIoc;
|
||||
using Newtonsoft.Json;
|
||||
using SkiaSharp;
|
||||
|
||||
@ -13,31 +11,8 @@ namespace Artemis.Core.Services;
|
||||
|
||||
internal class NodeService : INodeService
|
||||
{
|
||||
#region Constants
|
||||
|
||||
private static readonly Type TypeNode = typeof(INode);
|
||||
|
||||
#endregion
|
||||
|
||||
private readonly IContainer _container;
|
||||
|
||||
#region Constructors
|
||||
|
||||
public NodeService(IContainer container)
|
||||
{
|
||||
_container = container;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Properties & Fields
|
||||
|
||||
public IEnumerable<NodeData> AvailableNodes => NodeTypeStore.GetAll();
|
||||
|
||||
#endregion
|
||||
|
||||
#region Methods
|
||||
|
||||
/// <inheritdoc />
|
||||
public List<Type> GetRegisteredTypes()
|
||||
{
|
||||
@ -53,7 +28,7 @@ internal class NodeService : INodeService
|
||||
|
||||
// Objects represent an input that can take any type, these are hardcoded white
|
||||
if (type == typeof(object))
|
||||
return new TypeColorRegistration(type, new SKColor(255, 255, 255, 255), Constants.CorePlugin);
|
||||
return new TypeColorRegistration(type, new SKColor(255, 255, 255, 255), Constants.CorePluginFeature);
|
||||
|
||||
// Come up with a random color based on the type name that should be the same each time
|
||||
MD5 md5Hasher = MD5.Create();
|
||||
@ -61,32 +36,7 @@ internal class NodeService : INodeService
|
||||
int hash = BitConverter.ToInt32(hashed, 0);
|
||||
|
||||
SKColor baseColor = SKColor.FromHsl(hash % 255, 50 + hash % 50, 50);
|
||||
return new TypeColorRegistration(type, baseColor, Constants.CorePlugin);
|
||||
}
|
||||
|
||||
public NodeTypeRegistration RegisterNodeType(Plugin plugin, Type nodeType)
|
||||
{
|
||||
if (plugin == null) throw new ArgumentNullException(nameof(plugin));
|
||||
if (nodeType == null) throw new ArgumentNullException(nameof(nodeType));
|
||||
|
||||
if (!TypeNode.IsAssignableFrom(nodeType)) throw new ArgumentException("Node has to be a base type of the Node-Type.", nameof(nodeType));
|
||||
|
||||
NodeAttribute? nodeAttribute = nodeType.GetCustomAttribute<NodeAttribute>();
|
||||
string name = nodeAttribute?.Name ?? nodeType.Name;
|
||||
string description = nodeAttribute?.Description ?? string.Empty;
|
||||
string category = nodeAttribute?.Category ?? string.Empty;
|
||||
string helpUrl = nodeAttribute?.HelpUrl ?? string.Empty;
|
||||
|
||||
NodeData nodeData = new(plugin, nodeType, name, description, category, helpUrl, nodeAttribute?.InputType, nodeAttribute?.OutputType, (s, e) => CreateNode(s, e, nodeType));
|
||||
return NodeTypeStore.Add(nodeData);
|
||||
}
|
||||
|
||||
public TypeColorRegistration RegisterTypeColor(Plugin plugin, Type type, SKColor color)
|
||||
{
|
||||
if (plugin == null) throw new ArgumentNullException(nameof(plugin));
|
||||
if (type == null) throw new ArgumentNullException(nameof(type));
|
||||
|
||||
return NodeTypeStore.AddColor(type, color, plugin);
|
||||
return new TypeColorRegistration(type, baseColor, Constants.CorePluginFeature);
|
||||
}
|
||||
|
||||
public string ExportScript(NodeScript nodeScript)
|
||||
@ -103,33 +53,6 @@ internal class NodeService : INodeService
|
||||
|
||||
target.LoadFromEntity(entity);
|
||||
}
|
||||
|
||||
private INode CreateNode(INodeScript script, NodeEntity? entity, Type nodeType)
|
||||
{
|
||||
INode node = _container.Resolve(nodeType) as INode ?? throw new InvalidOperationException($"Node {nodeType} is not an INode");
|
||||
if (node is Node concreteNode)
|
||||
concreteNode.Container = _container;
|
||||
|
||||
if (entity != null)
|
||||
{
|
||||
node.X = entity.X;
|
||||
node.Y = entity.Y;
|
||||
try
|
||||
{
|
||||
if (node is Node nodeImplementation)
|
||||
nodeImplementation.DeserializeStorage(entity.Storage);
|
||||
}
|
||||
catch
|
||||
{
|
||||
// ignored
|
||||
}
|
||||
}
|
||||
|
||||
node.TryInitialize(script);
|
||||
return node;
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@ -153,21 +76,6 @@ public interface INodeService : IArtemisService
|
||||
/// </summary>
|
||||
TypeColorRegistration GetTypeColorRegistration(Type type);
|
||||
|
||||
/// <summary>
|
||||
/// Registers a node of the provided <paramref name="nodeType" />
|
||||
/// </summary>
|
||||
/// <param name="plugin">The plugin the node belongs to</param>
|
||||
/// <param name="nodeType">The type of node to initialize</param>
|
||||
NodeTypeRegistration RegisterNodeType(Plugin plugin, Type nodeType);
|
||||
|
||||
/// <summary>
|
||||
/// Registers a type with a provided color for use in the node editor
|
||||
/// </summary>
|
||||
/// <param name="plugin">The plugin making the registration</param>
|
||||
/// <param name="type">The type to associate the color with</param>
|
||||
/// <param name="color">The color to display</param>
|
||||
TypeColorRegistration RegisterTypeColor(Plugin plugin, Type type, SKColor color);
|
||||
|
||||
/// <summary>
|
||||
/// Exports the provided node script to JSON.
|
||||
/// </summary>
|
||||
|
||||
@ -7,6 +7,9 @@ using System.Threading;
|
||||
|
||||
namespace Artemis.Core.Services;
|
||||
|
||||
/// <summary>
|
||||
/// Represents a monitor that efficiently keeps track of running processes.
|
||||
/// </summary>
|
||||
public static partial class ProcessMonitor
|
||||
{
|
||||
#region Properties & Fields
|
||||
@ -15,8 +18,11 @@ public static partial class ProcessMonitor
|
||||
|
||||
private static Timer? _timer;
|
||||
|
||||
private static Dictionary<int, ProcessInfo> _processes = new();
|
||||
private static readonly Dictionary<int, ProcessInfo> _processes = new();
|
||||
|
||||
/// <summary>
|
||||
/// Gets an immutable array of the current processes.
|
||||
/// </summary>
|
||||
public static ImmutableArray<ProcessInfo> Processes
|
||||
{
|
||||
get
|
||||
@ -25,9 +31,17 @@ public static partial class ProcessMonitor
|
||||
return _processes.Values.ToImmutableArray();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the date time at which the last update took place.
|
||||
/// </summary>
|
||||
public static DateTime LastUpdate { get; private set; }
|
||||
|
||||
private static TimeSpan _updateInterval = TimeSpan.FromSeconds(1);
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the interval at which to update the list of processes.
|
||||
/// </summary>
|
||||
public static TimeSpan UpdateInterval
|
||||
{
|
||||
get => _updateInterval;
|
||||
@ -40,6 +54,9 @@ public static partial class ProcessMonitor
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets a value indicating whether the monitoring has started.
|
||||
/// </summary>
|
||||
public static bool IsStarted
|
||||
{
|
||||
get
|
||||
@ -53,7 +70,14 @@ public static partial class ProcessMonitor
|
||||
|
||||
#region Events
|
||||
|
||||
/// <summary>
|
||||
/// Occurs when a new process is started.
|
||||
/// </summary>
|
||||
public static event EventHandler<ProcessEventArgs>? ProcessStarted;
|
||||
|
||||
/// <summary>
|
||||
/// Occurs when a process is stopped.
|
||||
/// </summary>
|
||||
public static event EventHandler<ProcessEventArgs>? ProcessStopped;
|
||||
|
||||
#endregion
|
||||
@ -69,6 +93,9 @@ public static partial class ProcessMonitor
|
||||
|
||||
#region Methods
|
||||
|
||||
/// <summary>
|
||||
/// Starts monitoring processes.
|
||||
/// </summary>
|
||||
public static void Start()
|
||||
{
|
||||
lock (LOCK)
|
||||
@ -87,6 +114,9 @@ public static partial class ProcessMonitor
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Stops monitoring processes.
|
||||
/// </summary>
|
||||
public static void Stop()
|
||||
{
|
||||
lock (LOCK)
|
||||
@ -100,7 +130,7 @@ public static partial class ProcessMonitor
|
||||
FreeBuffer();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Returns whether the specified process is running
|
||||
/// </summary>
|
||||
@ -111,7 +141,7 @@ public static partial class ProcessMonitor
|
||||
{
|
||||
if (!IsStarted || (processName == null && processLocation == null))
|
||||
return false;
|
||||
|
||||
|
||||
lock (LOCK)
|
||||
{
|
||||
return _processes.Values.Any(x => IsProcessRunning(x, processName, processLocation));
|
||||
@ -130,19 +160,19 @@ public static partial class ProcessMonitor
|
||||
OnProcessStopped(info);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private static bool IsProcessRunning(ProcessInfo info, string? processName, string? processLocation)
|
||||
{
|
||||
if (processName != null && processLocation != null)
|
||||
return string.Equals(info.ProcessName, processName, StringComparison.InvariantCultureIgnoreCase) &&
|
||||
string.Equals(Path.GetDirectoryName(info.Executable), processLocation, StringComparison.InvariantCultureIgnoreCase);
|
||||
|
||||
|
||||
if (processName != null)
|
||||
return string.Equals(info.ProcessName, processName, StringComparison.InvariantCultureIgnoreCase);
|
||||
|
||||
|
||||
if (processLocation != null)
|
||||
return string.Equals(Path.GetDirectoryName(info.Executable), processLocation, StringComparison.InvariantCultureIgnoreCase);
|
||||
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
@ -152,7 +182,10 @@ public static partial class ProcessMonitor
|
||||
{
|
||||
ProcessStarted?.Invoke(null, new ProcessEventArgs(processInfo));
|
||||
}
|
||||
catch { /* Subscribers are idiots! */ }
|
||||
catch
|
||||
{
|
||||
/* Subscribers are idiots! */
|
||||
}
|
||||
}
|
||||
|
||||
private static void OnProcessStopped(ProcessInfo processInfo)
|
||||
@ -161,7 +194,10 @@ public static partial class ProcessMonitor
|
||||
{
|
||||
ProcessStopped?.Invoke(null, new ProcessEventArgs(processInfo));
|
||||
}
|
||||
catch { /* Subscribers are idiots! */ }
|
||||
catch
|
||||
{
|
||||
/* Subscribers are idiots! */
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
@ -42,6 +42,7 @@ internal class LayerBrushService : ILayerBrushService
|
||||
BrushType = "SolidBrush"
|
||||
});
|
||||
|
||||
defaultReference.Value ??= new LayerBrushReference();
|
||||
defaultReference.Value.LayerBrushProviderId ??= "Artemis.Plugins.LayerBrushes.Color.ColorBrushProvider-92a9d6ba";
|
||||
defaultReference.Value.BrushType ??= "SolidBrush";
|
||||
return LayerBrushStore.Get(defaultReference.Value.LayerBrushProviderId, defaultReference.Value.BrushType)?.LayerBrushDescriptor;
|
||||
|
||||
@ -8,8 +8,10 @@ using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using Artemis.Core.Modules;
|
||||
using Artemis.Storage.Entities.Profile;
|
||||
using Artemis.Storage.Migrations;
|
||||
using Artemis.Storage.Repositories.Interfaces;
|
||||
using Newtonsoft.Json;
|
||||
using Newtonsoft.Json.Linq;
|
||||
using Serilog;
|
||||
using SkiaSharp;
|
||||
|
||||
@ -24,9 +26,10 @@ internal class ProfileService : IProfileService
|
||||
private readonly List<ArtemisKeyboardKeyEventArgs> _pendingKeyboardEvents = new();
|
||||
private readonly List<ProfileCategory> _profileCategories;
|
||||
private readonly IProfileRepository _profileRepository;
|
||||
private readonly List<IProfileMigration> _profileMigrators;
|
||||
private readonly List<Exception> _renderExceptions = new();
|
||||
private readonly List<Exception> _updateExceptions = new();
|
||||
|
||||
|
||||
private DateTime _lastRenderExceptionLog;
|
||||
private DateTime _lastUpdateExceptionLog;
|
||||
|
||||
@ -35,13 +38,15 @@ internal class ProfileService : IProfileService
|
||||
IPluginManagementService pluginManagementService,
|
||||
IInputService inputService,
|
||||
IDeviceService deviceService,
|
||||
IProfileRepository profileRepository)
|
||||
IProfileRepository profileRepository,
|
||||
List<IProfileMigration> profileMigrators)
|
||||
{
|
||||
_logger = logger;
|
||||
_profileCategoryRepository = profileCategoryRepository;
|
||||
_pluginManagementService = pluginManagementService;
|
||||
_deviceService = deviceService;
|
||||
_profileRepository = profileRepository;
|
||||
_profileMigrators = profileMigrators;
|
||||
_profileCategories = new List<ProfileCategory>(_profileCategoryRepository.GetAll().Select(c => new ProfileCategory(c)).OrderBy(c => c.Order));
|
||||
|
||||
_deviceService.LedsChanged += DeviceServiceOnLedsChanged;
|
||||
@ -58,7 +63,7 @@ internal class ProfileService : IProfileService
|
||||
public ProfileConfiguration? FocusProfile { get; set; }
|
||||
public ProfileElement? FocusProfileElement { get; set; }
|
||||
public bool UpdateFocusProfile { get; set; }
|
||||
|
||||
|
||||
public bool ProfileRenderingDisabled { get; set; }
|
||||
|
||||
/// <inheritdoc />
|
||||
@ -221,7 +226,7 @@ internal class ProfileService : IProfileService
|
||||
return profileConfiguration.Profile;
|
||||
}
|
||||
|
||||
ProfileEntity profileEntity;
|
||||
ProfileEntity? profileEntity;
|
||||
try
|
||||
{
|
||||
profileEntity = _profileRepository.Get(profileConfiguration.Entity.ProfileId);
|
||||
@ -280,7 +285,7 @@ internal class ProfileService : IProfileService
|
||||
{
|
||||
DeactivateProfile(profileConfiguration);
|
||||
|
||||
ProfileEntity profileEntity = _profileRepository.Get(profileConfiguration.Entity.ProfileId);
|
||||
ProfileEntity? profileEntity = _profileRepository.Get(profileConfiguration.Entity.ProfileId);
|
||||
if (profileEntity == null)
|
||||
return;
|
||||
|
||||
@ -353,7 +358,7 @@ internal class ProfileService : IProfileService
|
||||
|
||||
DeactivateProfile(profileConfiguration);
|
||||
SaveProfileCategory(profileConfiguration.Category);
|
||||
ProfileEntity profileEntity = _profileRepository.Get(profileConfiguration.Entity.ProfileId);
|
||||
ProfileEntity? profileEntity = _profileRepository.Get(profileConfiguration.Entity.ProfileId);
|
||||
if (profileEntity != null)
|
||||
_profileRepository.Remove(profileEntity);
|
||||
|
||||
@ -461,7 +466,12 @@ internal class ProfileService : IProfileService
|
||||
|
||||
await using Stream profileStream = profileEntry.Open();
|
||||
using StreamReader profileReader = new(profileStream);
|
||||
ProfileEntity? profileEntity = JsonConvert.DeserializeObject<ProfileEntity>(await profileReader.ReadToEndAsync(), IProfileService.ExportSettings);
|
||||
JObject? profileJson = JsonConvert.DeserializeObject<JObject>(await profileReader.ReadToEndAsync(), IProfileService.ExportSettings);
|
||||
|
||||
// Before deserializing, apply any pending migrations
|
||||
MigrateProfile(configurationEntity, profileJson);
|
||||
|
||||
ProfileEntity? profileEntity = profileJson?.ToObject<ProfileEntity>(JsonSerializer.Create(IProfileService.ExportSettings));
|
||||
if (profileEntity == null)
|
||||
throw new ArtemisCoreException("Could not import profile, failed to deserialize profile.json");
|
||||
|
||||
@ -514,10 +524,10 @@ internal class ProfileService : IProfileService
|
||||
public async Task<ProfileConfiguration> OverwriteProfile(MemoryStream archiveStream, ProfileConfiguration profileConfiguration)
|
||||
{
|
||||
ProfileConfiguration imported = await ImportProfile(archiveStream, profileConfiguration.Category, true, true, null, profileConfiguration.Order + 1);
|
||||
|
||||
|
||||
DeleteProfile(profileConfiguration);
|
||||
SaveProfileCategory(imported.Category);
|
||||
|
||||
|
||||
return imported;
|
||||
}
|
||||
|
||||
@ -545,6 +555,21 @@ internal class ProfileService : IProfileService
|
||||
}
|
||||
}
|
||||
|
||||
private void MigrateProfile(ProfileConfigurationEntity configurationEntity, JObject? profileJson)
|
||||
{
|
||||
if (profileJson == null)
|
||||
return;
|
||||
|
||||
foreach (IProfileMigration profileMigrator in _profileMigrators.OrderBy(m => m.Version))
|
||||
{
|
||||
if (profileMigrator.Version <= configurationEntity.Version)
|
||||
continue;
|
||||
|
||||
profileMigrator.Migrate(profileJson);
|
||||
configurationEntity.Version = profileMigrator.Version;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Populates all missing LEDs on all currently active profiles
|
||||
/// </summary>
|
||||
|
||||
@ -100,7 +100,7 @@ public interface IWebServerService : IArtemisService
|
||||
/// <summary>
|
||||
/// Removes an existing Web API controller and restarts the web server
|
||||
/// </summary>
|
||||
/// <typeparam name="T">The type of Web API controller to remove</typeparam>
|
||||
/// <param name="registration">The registration of the controller to remove.</param>
|
||||
void RemoveController(WebApiControllerRegistration registration);
|
||||
|
||||
/// <summary>
|
||||
|
||||
@ -13,16 +13,13 @@ internal class NodeTypeStore
|
||||
|
||||
public static NodeTypeRegistration Add(NodeData nodeData)
|
||||
{
|
||||
if (nodeData.Plugin == null)
|
||||
throw new ArtemisCoreException("Cannot add a data binding modifier type that is not associated with a plugin");
|
||||
|
||||
NodeTypeRegistration typeRegistration;
|
||||
lock (Registrations)
|
||||
{
|
||||
if (Registrations.Any(r => r.NodeData == nodeData))
|
||||
throw new ArtemisCoreException($"Data binding modifier type store already contains modifier '{nodeData.Name}'");
|
||||
|
||||
typeRegistration = new NodeTypeRegistration(nodeData, nodeData.Plugin) {IsInStore = true};
|
||||
typeRegistration = new NodeTypeRegistration(nodeData, nodeData.Provider) {IsInStore = true};
|
||||
Registrations.Add(typeRegistration);
|
||||
}
|
||||
|
||||
@ -60,24 +57,12 @@ internal class NodeTypeStore
|
||||
}
|
||||
}
|
||||
|
||||
public static Plugin? GetPlugin(INode node)
|
||||
{
|
||||
Type nodeType = node.GetType();
|
||||
lock (Registrations)
|
||||
{
|
||||
return Registrations.FirstOrDefault(r => r.NodeData.Type == nodeType)?.Plugin;
|
||||
}
|
||||
}
|
||||
|
||||
public static TypeColorRegistration AddColor(Type type, SKColor color, Plugin plugin)
|
||||
public static TypeColorRegistration AddColor(Type type, SKColor color, PluginFeature pluginFeature)
|
||||
{
|
||||
TypeColorRegistration typeColorRegistration;
|
||||
lock (ColorRegistrations)
|
||||
{
|
||||
if (ColorRegistrations.Any(r => r.Type == type))
|
||||
throw new ArtemisCoreException($"Node color store already contains a color for '{type.Name}'");
|
||||
|
||||
typeColorRegistration = new TypeColorRegistration(type, color, plugin) {IsInStore = true};
|
||||
typeColorRegistration = new TypeColorRegistration(type, color, pluginFeature) {IsInStore = true};
|
||||
ColorRegistrations.Add(typeColorRegistration);
|
||||
}
|
||||
|
||||
|
||||
@ -9,12 +9,12 @@ namespace Artemis.Core;
|
||||
/// </summary>
|
||||
public class NodeTypeRegistration
|
||||
{
|
||||
internal NodeTypeRegistration(NodeData nodeData, Plugin plugin)
|
||||
internal NodeTypeRegistration(NodeData nodeData, PluginFeature pluginFeature)
|
||||
{
|
||||
NodeData = nodeData;
|
||||
Plugin = plugin;
|
||||
PluginFeature = pluginFeature;
|
||||
|
||||
Plugin.Disabled += OnDisabled;
|
||||
PluginFeature.Disabled += OnDisabled;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@ -23,9 +23,9 @@ public class NodeTypeRegistration
|
||||
public NodeData NodeData { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the plugin the node is associated with
|
||||
/// Gets the plugin feature the node is associated with
|
||||
/// </summary>
|
||||
public Plugin Plugin { get; }
|
||||
public PluginFeature PluginFeature { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets a boolean indicating whether the registration is in the internal Core store
|
||||
@ -39,12 +39,12 @@ public class NodeTypeRegistration
|
||||
/// <returns><see langword="true" /> if the entity matches this registration; otherwise <see langword="false" />.</returns>
|
||||
public bool MatchesEntity(NodeEntity entity)
|
||||
{
|
||||
return Plugin.Guid == entity.PluginId && NodeData.Type.Name == entity.Type;
|
||||
return PluginFeature.Id == entity.ProviderId && NodeData.Type.Name == entity.Type;
|
||||
}
|
||||
|
||||
private void OnDisabled(object? sender, EventArgs e)
|
||||
{
|
||||
Plugin.Disabled -= OnDisabled;
|
||||
PluginFeature.Disabled -= OnDisabled;
|
||||
if (IsInStore)
|
||||
NodeTypeStore.Remove(this);
|
||||
}
|
||||
@ -55,13 +55,13 @@ public class NodeTypeRegistration
|
||||
/// </summary>
|
||||
public class TypeColorRegistration
|
||||
{
|
||||
internal TypeColorRegistration(Type type, SKColor color, Plugin plugin)
|
||||
internal TypeColorRegistration(Type type, SKColor color, PluginFeature pluginFeature)
|
||||
{
|
||||
Type = type;
|
||||
Color = color;
|
||||
Plugin = plugin;
|
||||
PluginFeature = pluginFeature;
|
||||
|
||||
Plugin.Disabled += OnDisabled;
|
||||
PluginFeature.Disabled += OnDisabled;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@ -80,9 +80,9 @@ public class TypeColorRegistration
|
||||
public SKColor DarkenedColor => Color.Darken(0.35f);
|
||||
|
||||
/// <summary>
|
||||
/// Gets the plugin type color is associated with
|
||||
/// Gets the plugin feature this type color is associated with
|
||||
/// </summary>
|
||||
public Plugin Plugin { get; }
|
||||
public PluginFeature PluginFeature { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets a boolean indicating whether the registration is in the internal Core store
|
||||
@ -91,7 +91,7 @@ public class TypeColorRegistration
|
||||
|
||||
private void OnDisabled(object? sender, EventArgs e)
|
||||
{
|
||||
Plugin.Disabled -= OnDisabled;
|
||||
PluginFeature.Disabled -= OnDisabled;
|
||||
if (IsInStore)
|
||||
NodeTypeStore.RemoveColor(this);
|
||||
}
|
||||
|
||||
@ -14,6 +14,11 @@ public interface INode : INotifyPropertyChanged, IBreakableModel
|
||||
/// Gets or sets the ID of the node.
|
||||
/// </summary>
|
||||
Guid Id { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the node data with information about this node
|
||||
/// </summary>
|
||||
NodeData? NodeData { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the name of the node
|
||||
|
||||
@ -1,4 +1,5 @@
|
||||
using System;
|
||||
using Artemis.Core.Nodes;
|
||||
using Artemis.Storage.Entities.Profile.Nodes;
|
||||
|
||||
namespace Artemis.Core;
|
||||
@ -10,9 +11,9 @@ public class NodeData
|
||||
{
|
||||
#region Constructors
|
||||
|
||||
internal NodeData(Plugin plugin, Type type, string name, string description, string category, string helpUrl, Type? inputType, Type? outputType, Func<INodeScript, NodeEntity?, INode> create)
|
||||
internal NodeData(NodeProvider provider, Type type, string name, string description, string category, string helpUrl, Type? inputType, Type? outputType)
|
||||
{
|
||||
Plugin = plugin;
|
||||
Provider = provider;
|
||||
Type = type;
|
||||
Name = name;
|
||||
Description = description;
|
||||
@ -20,7 +21,6 @@ public class NodeData
|
||||
HelpUrl = helpUrl;
|
||||
InputType = inputType;
|
||||
OutputType = outputType;
|
||||
_create = create;
|
||||
}
|
||||
|
||||
#endregion
|
||||
@ -35,14 +35,31 @@ public class NodeData
|
||||
/// <returns>The returning node of type <see cref="Type" /></returns>
|
||||
public INode CreateNode(INodeScript script, NodeEntity? entity)
|
||||
{
|
||||
INode node = _create(script, entity);
|
||||
INode node = (INode) Provider.Plugin.Resolve(Type);
|
||||
node.NodeData = this;
|
||||
if (string.IsNullOrWhiteSpace(node.Name))
|
||||
node.Name = Name;
|
||||
if (string.IsNullOrWhiteSpace(node.Description))
|
||||
node.Description = Description;
|
||||
if (string.IsNullOrWhiteSpace(node.HelpUrl))
|
||||
node.HelpUrl = HelpUrl;
|
||||
|
||||
if (entity != null)
|
||||
{
|
||||
node.X = entity.X;
|
||||
node.Y = entity.Y;
|
||||
try
|
||||
{
|
||||
if (node is Node nodeImplementation)
|
||||
nodeImplementation.DeserializeStorage(entity.Storage);
|
||||
}
|
||||
catch
|
||||
{
|
||||
// ignored
|
||||
}
|
||||
}
|
||||
|
||||
node.TryInitialize(script);
|
||||
return node;
|
||||
}
|
||||
|
||||
@ -91,11 +108,11 @@ public class NodeData
|
||||
}
|
||||
|
||||
#region Properties & Fields
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Gets the plugin that provided this node data
|
||||
/// Gets the node provider that provided this node data
|
||||
/// </summary>
|
||||
public Plugin Plugin { get; }
|
||||
public NodeProvider Provider { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the type of <see cref="INode" /> this data represents
|
||||
@ -132,7 +149,5 @@ public class NodeData
|
||||
/// </summary>
|
||||
public Type? OutputType { get; }
|
||||
|
||||
private readonly Func<INodeScript, NodeEntity?, INode> _create;
|
||||
|
||||
#endregion
|
||||
}
|
||||
@ -161,6 +161,7 @@ public abstract class NodeScript : CorePropertyChanged, INodeScript
|
||||
{
|
||||
foreach (INode node in _nodes)
|
||||
{
|
||||
// ReSharper disable once SuspiciousTypeConversion.Global - Provided by plugins
|
||||
if (node is IDisposable disposable)
|
||||
disposable.Dispose();
|
||||
}
|
||||
@ -181,6 +182,7 @@ public abstract class NodeScript : CorePropertyChanged, INodeScript
|
||||
foreach (INode removeNode in removeNodes)
|
||||
{
|
||||
RemoveNode(removeNode);
|
||||
// ReSharper disable once SuspiciousTypeConversion.Global - Provided by plugins
|
||||
if (removeNode is IDisposable disposable)
|
||||
disposable.Dispose();
|
||||
}
|
||||
@ -312,7 +314,7 @@ public abstract class NodeScript : CorePropertyChanged, INodeScript
|
||||
NodeEntity nodeEntity = new()
|
||||
{
|
||||
Id = node.Id,
|
||||
PluginId = NodeTypeStore.GetPlugin(node)?.Guid ?? Constants.CorePlugin.Guid,
|
||||
ProviderId = node.NodeData?.Provider.Id ?? Constants.CorePluginFeature.Id,
|
||||
Type = node.GetType().Name,
|
||||
X = node.X,
|
||||
Y = node.Y,
|
||||
|
||||
@ -41,6 +41,9 @@ public abstract class Node : BreakableModel, INode
|
||||
set => SetAndNotify(ref _id, value);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public NodeData? NodeData { get; set; }
|
||||
|
||||
private string _name;
|
||||
|
||||
/// <inheritdoc />
|
||||
@ -104,8 +107,6 @@ public abstract class Node : BreakableModel, INode
|
||||
/// <inheritdoc />
|
||||
public override string BrokenDisplayName => Name;
|
||||
|
||||
internal IContainer Container { get; set; } = null!;
|
||||
|
||||
#endregion
|
||||
|
||||
#region Construtors
|
||||
|
||||
@ -25,7 +25,9 @@ public abstract class Node<TStorage, TViewModel> : Node<TStorage>, ICustomViewMo
|
||||
/// <param name="nodeScript"></param>
|
||||
public virtual TViewModel GetViewModel(NodeScript nodeScript)
|
||||
{
|
||||
return Container.Resolve<TViewModel>(args: new object[] {this, nodeScript});
|
||||
if (NodeData == null)
|
||||
throw new ArtemisCoreException("Nodes without node data (default nodes or exit nodes) cannot have custom view models");
|
||||
return NodeData.Provider.Plugin.Container.Resolve<TViewModel>(args: new object[] {this, nodeScript});
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
||||
@ -1,12 +1,14 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net7.0</TargetFramework>
|
||||
<TargetFramework>net8.0</TargetFramework>
|
||||
<PreserveCompilationContext>false</PreserveCompilationContext>
|
||||
<Platforms>x64</Platforms>
|
||||
<Nullable>enable</Nullable>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="LiteDB" Version="5.0.17" />
|
||||
<PackageReference Include="Serilog" Version="3.1.1" />
|
||||
<PackageReference Include="LiteDB" />
|
||||
<PackageReference Include="Serilog" />
|
||||
<PackageReference Include="Newtonsoft.Json" />
|
||||
</ItemGroup>
|
||||
</Project>
|
||||
@ -11,7 +11,7 @@ public class QueuedActionEntity
|
||||
}
|
||||
|
||||
public Guid Id { get; set; }
|
||||
public string Type { get; set; }
|
||||
public string Type { get; set; } = string.Empty;
|
||||
public DateTimeOffset CreatedAt { get; set; }
|
||||
|
||||
public Dictionary<string, object> Parameters { get; set; }
|
||||
|
||||
@ -6,6 +6,6 @@ public class ReleaseEntity
|
||||
{
|
||||
public Guid Id { get; set; }
|
||||
|
||||
public string Version { get; set; }
|
||||
public string Version { get; set; } = string.Empty;
|
||||
public DateTimeOffset? InstalledAt { get; set; }
|
||||
}
|
||||
@ -6,7 +6,7 @@ public class ScriptConfigurationEntity
|
||||
{
|
||||
public Guid Id { get; set; }
|
||||
|
||||
public string Name { get; set; }
|
||||
public string ScriptingProviderId { get; set; }
|
||||
public string ScriptContent { get; set; }
|
||||
public string Name { get; set; } = string.Empty;
|
||||
public string ScriptingProviderId { get; set; } = string.Empty;
|
||||
public string? ScriptContent { get; set; }
|
||||
}
|
||||
@ -24,6 +24,6 @@ public class PluginEntity
|
||||
/// </summary>
|
||||
public class PluginFeatureEntity
|
||||
{
|
||||
public string Type { get; set; }
|
||||
public string Type { get; set; } = string.Empty;
|
||||
public bool IsEnabled { get; set; }
|
||||
}
|
||||
@ -10,6 +10,6 @@ public class PluginSettingEntity
|
||||
public Guid Id { get; set; }
|
||||
public Guid PluginGuid { get; set; }
|
||||
|
||||
public string Name { get; set; }
|
||||
public string Value { get; set; }
|
||||
public string Name { get; set; } = string.Empty;
|
||||
public string Value { get; set; } = string.Empty;
|
||||
}
|
||||
@ -1,8 +0,0 @@
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Artemis.Storage.Entities.Profile.Abstract;
|
||||
|
||||
public abstract class DataModelConditionPartEntity
|
||||
{
|
||||
public List<DataModelConditionPartEntity> Children { get; set; }
|
||||
}
|
||||
@ -8,8 +8,8 @@ public abstract class RenderElementEntity
|
||||
public Guid Id { get; set; }
|
||||
public Guid ParentId { get; set; }
|
||||
|
||||
public List<LayerEffectEntity> LayerEffects { get; set; }
|
||||
public List<LayerEffectEntity> LayerEffects { get; set; } = new();
|
||||
|
||||
public IConditionEntity DisplayCondition { get; set; }
|
||||
public TimelineEntity Timeline { get; set; }
|
||||
public IConditionEntity? DisplayCondition { get; set; }
|
||||
public TimelineEntity? Timeline { get; set; }
|
||||
}
|
||||
@ -1,5 +1,3 @@
|
||||
namespace Artemis.Storage.Entities.Profile.AdaptionHints;
|
||||
|
||||
public interface IAdaptionHintEntity
|
||||
{
|
||||
}
|
||||
public interface IAdaptionHintEntity;
|
||||
@ -2,6 +2,4 @@
|
||||
|
||||
namespace Artemis.Storage.Entities.Profile.Conditions;
|
||||
|
||||
public class AlwaysOnConditionEntity : IConditionEntity
|
||||
{
|
||||
}
|
||||
public class AlwaysOnConditionEntity : IConditionEntity;
|
||||
@ -8,6 +8,6 @@ public class EventConditionEntity : IConditionEntity
|
||||
public int TriggerMode { get; set; }
|
||||
public int OverlapMode { get; set; }
|
||||
public int ToggleOffMode { get; set; }
|
||||
public DataModelPathEntity EventPath { get; set; }
|
||||
public NodeScriptEntity Script { get; set; }
|
||||
public DataModelPathEntity? EventPath { get; set; }
|
||||
public NodeScriptEntity? Script { get; set; }
|
||||
}
|
||||
@ -1,5 +1,3 @@
|
||||
namespace Artemis.Storage.Entities.Profile.Abstract;
|
||||
|
||||
public interface IConditionEntity
|
||||
{
|
||||
}
|
||||
public interface IConditionEntity;
|
||||
@ -2,6 +2,4 @@
|
||||
|
||||
namespace Artemis.Storage.Entities.Profile.Conditions;
|
||||
|
||||
public class PlayOnceConditionEntity : IConditionEntity
|
||||
{
|
||||
}
|
||||
public class PlayOnceConditionEntity : IConditionEntity;
|
||||
@ -7,5 +7,5 @@ public class StaticConditionEntity : IConditionEntity
|
||||
{
|
||||
public int PlayMode { get; set; }
|
||||
public int StopMode { get; set; }
|
||||
public NodeScriptEntity Script { get; set; }
|
||||
public NodeScriptEntity? Script { get; set; }
|
||||
}
|
||||
@ -4,7 +4,6 @@ namespace Artemis.Storage.Entities.Profile.DataBindings;
|
||||
|
||||
public class DataBindingEntity
|
||||
{
|
||||
public string Identifier { get; set; }
|
||||
public bool IsEnabled { get; set; }
|
||||
public NodeScriptEntity NodeScript { get; set; }
|
||||
public NodeScriptEntity? NodeScript { get; set; }
|
||||
}
|
||||
@ -2,7 +2,7 @@
|
||||
|
||||
public class DataModelPathEntity
|
||||
{
|
||||
public string Path { get; set; }
|
||||
public string DataModelId { get; set; }
|
||||
public string Type { get; set; }
|
||||
public string Path { get; set; } = string.Empty;
|
||||
public string? DataModelId { get; set; }
|
||||
public string? Type { get; set; }
|
||||
}
|
||||
@ -1,5 +1,4 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using Artemis.Storage.Entities.Profile.Abstract;
|
||||
using LiteDB;
|
||||
|
||||
@ -7,18 +6,13 @@ namespace Artemis.Storage.Entities.Profile;
|
||||
|
||||
public class FolderEntity : RenderElementEntity
|
||||
{
|
||||
public FolderEntity()
|
||||
{
|
||||
LayerEffects = new List<LayerEffectEntity>();
|
||||
}
|
||||
|
||||
public int Order { get; set; }
|
||||
public string Name { get; set; }
|
||||
public string? Name { get; set; }
|
||||
public bool IsExpanded { get; set; }
|
||||
public bool Suspended { get; set; }
|
||||
|
||||
[BsonRef("ProfileEntity")]
|
||||
public ProfileEntity Profile { get; set; }
|
||||
public ProfileEntity Profile { get; set; } = null!;
|
||||
|
||||
public Guid ProfileId { get; set; }
|
||||
}
|
||||
@ -6,6 +6,6 @@ public class KeyframeEntity
|
||||
{
|
||||
public TimeSpan Position { get; set; }
|
||||
public int Timeline { get; set; }
|
||||
public string Value { get; set; }
|
||||
public string Value { get; set; } = string.Empty;
|
||||
public int EasingFunction { get; set; }
|
||||
}
|
||||
@ -2,8 +2,8 @@
|
||||
|
||||
public class LayerBrushEntity
|
||||
{
|
||||
public string ProviderId { get; set; }
|
||||
public string BrushType { get; set; }
|
||||
public string ProviderId { get; set; } = string.Empty;
|
||||
public string BrushType { get; set; } = string.Empty;
|
||||
|
||||
public PropertyGroupEntity PropertyGroup { get; set; }
|
||||
public PropertyGroupEntity? PropertyGroup { get; set; }
|
||||
}
|
||||
@ -2,11 +2,11 @@
|
||||
|
||||
public class LayerEffectEntity
|
||||
{
|
||||
public string ProviderId { get; set; }
|
||||
public string EffectType { get; set; }
|
||||
public string Name { get; set; }
|
||||
public string ProviderId { get; set; } = string.Empty;
|
||||
public string EffectType { get; set; } = string.Empty;
|
||||
public string Name { get; set; } = string.Empty;
|
||||
public bool HasBeenRenamed { get; set; }
|
||||
public int Order { get; set; }
|
||||
|
||||
public PropertyGroupEntity PropertyGroup { get; set; }
|
||||
public PropertyGroupEntity? PropertyGroup { get; set; }
|
||||
}
|
||||
@ -12,22 +12,21 @@ public class LayerEntity : RenderElementEntity
|
||||
{
|
||||
Leds = new List<LedEntity>();
|
||||
AdaptionHints = new List<IAdaptionHintEntity>();
|
||||
LayerEffects = new List<LayerEffectEntity>();
|
||||
}
|
||||
|
||||
public int Order { get; set; }
|
||||
public string Name { get; set; }
|
||||
public string? Name { get; set; }
|
||||
public bool Suspended { get; set; }
|
||||
|
||||
public List<LedEntity> Leds { get; set; }
|
||||
public List<IAdaptionHintEntity> AdaptionHints { get; set; }
|
||||
|
||||
public PropertyGroupEntity GeneralPropertyGroup { get; set; }
|
||||
public PropertyGroupEntity TransformPropertyGroup { get; set; }
|
||||
public LayerBrushEntity LayerBrush { get; set; }
|
||||
public PropertyGroupEntity? GeneralPropertyGroup { get; set; }
|
||||
public PropertyGroupEntity? TransformPropertyGroup { get; set; }
|
||||
public LayerBrushEntity? LayerBrush { get; set; }
|
||||
|
||||
[BsonRef("ProfileEntity")]
|
||||
public ProfileEntity Profile { get; set; }
|
||||
public ProfileEntity Profile { get; set; } = null!;
|
||||
|
||||
public Guid ProfileId { get; set; }
|
||||
}
|
||||
@ -5,8 +5,8 @@ namespace Artemis.Storage.Entities.Profile;
|
||||
|
||||
public class LedEntity
|
||||
{
|
||||
public string LedName { get; set; }
|
||||
public string DeviceIdentifier { get; set; }
|
||||
public string LedName { get; set; } = string.Empty;
|
||||
public string DeviceIdentifier { get; set; } = string.Empty;
|
||||
|
||||
public int? PhysicalLayout { get; set; }
|
||||
|
||||
@ -14,7 +14,7 @@ public class LedEntity
|
||||
|
||||
private sealed class LedEntityEqualityComparer : IEqualityComparer<LedEntity>
|
||||
{
|
||||
public bool Equals(LedEntity x, LedEntity y)
|
||||
public bool Equals(LedEntity? x, LedEntity? y)
|
||||
{
|
||||
if (ReferenceEquals(x, y))
|
||||
return true;
|
||||
|
||||
@ -20,12 +20,12 @@ public class NodeConnectionEntity
|
||||
TargetPinId = nodeConnectionEntity.TargetPinId;
|
||||
}
|
||||
|
||||
public string SourceType { get; set; }
|
||||
public string SourceType { get; set; } = string.Empty;
|
||||
public Guid SourceNode { get; set; }
|
||||
public Guid TargetNode { get; set; }
|
||||
public int SourcePinCollectionId { get; set; }
|
||||
public int SourcePinId { get; set; }
|
||||
public string TargetType { get; set; }
|
||||
public string TargetType { get; set; } = string.Empty;
|
||||
public int TargetPinCollectionId { get; set; }
|
||||
public int TargetPinId { get; set; }
|
||||
}
|
||||
@ -1,4 +1,4 @@
|
||||
using System;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
|
||||
@ -15,7 +15,7 @@ public class NodeEntity
|
||||
{
|
||||
Id = nodeEntity.Id;
|
||||
Type = nodeEntity.Type;
|
||||
PluginId = nodeEntity.PluginId;
|
||||
ProviderId = nodeEntity.ProviderId;
|
||||
|
||||
Name = nodeEntity.Name;
|
||||
Description = nodeEntity.Description;
|
||||
@ -28,15 +28,15 @@ public class NodeEntity
|
||||
}
|
||||
|
||||
public Guid Id { get; set; }
|
||||
public string Type { get; set; }
|
||||
public Guid PluginId { get; set; }
|
||||
public string Type { get; set; } = string.Empty;
|
||||
public string ProviderId { get; set; } = string.Empty;
|
||||
|
||||
public string Name { get; set; }
|
||||
public string Description { get; set; }
|
||||
public string Name { get; set; } = string.Empty;
|
||||
public string Description { get; set; } = string.Empty;
|
||||
public bool IsExitNode { get; set; }
|
||||
public double X { get; set; }
|
||||
public double Y { get; set; }
|
||||
public string Storage { get; set; }
|
||||
public string Storage { get; set; } = string.Empty;
|
||||
|
||||
public List<NodePinCollectionEntity> PinCollections { get; set; }
|
||||
}
|
||||
@ -10,8 +10,8 @@ public class NodeScriptEntity
|
||||
Connections = new List<NodeConnectionEntity>();
|
||||
}
|
||||
|
||||
public string Name { get; set; }
|
||||
public string Description { get; set; }
|
||||
public string Name { get; set; } = string.Empty;
|
||||
public string Description { get; set; } = string.Empty;
|
||||
|
||||
public List<NodeEntity> Nodes { get; set; }
|
||||
public List<NodeConnectionEntity> Connections { get; set; }
|
||||
|
||||
@ -7,7 +7,7 @@ public class ProfileCategoryEntity
|
||||
{
|
||||
public Guid Id { get; set; }
|
||||
|
||||
public string Name { get; set; }
|
||||
public string Name { get; set; } = string.Empty;
|
||||
public bool IsCollapsed { get; set; }
|
||||
public bool IsSuspended { get; set; }
|
||||
public int Order { get; set; }
|
||||
|
||||
@ -5,8 +5,8 @@ namespace Artemis.Storage.Entities.Profile;
|
||||
|
||||
public class ProfileConfigurationEntity
|
||||
{
|
||||
public string Name { get; set; }
|
||||
public string MaterialIcon { get; set; }
|
||||
public string Name { get; set; } = string.Empty;
|
||||
public string? MaterialIcon { get; set; }
|
||||
public Guid FileIconId { get; set; }
|
||||
public int IconType { get; set; }
|
||||
public bool IconFill { get; set; }
|
||||
@ -14,16 +14,17 @@ public class ProfileConfigurationEntity
|
||||
|
||||
public bool IsSuspended { get; set; }
|
||||
public int ActivationBehaviour { get; set; }
|
||||
public NodeScriptEntity ActivationCondition { get; set; }
|
||||
public NodeScriptEntity? ActivationCondition { get; set; }
|
||||
|
||||
public int HotkeyMode { get; set; }
|
||||
public ProfileConfigurationHotkeyEntity EnableHotkey { get; set; }
|
||||
public ProfileConfigurationHotkeyEntity DisableHotkey { get; set; }
|
||||
public ProfileConfigurationHotkeyEntity? EnableHotkey { get; set; }
|
||||
public ProfileConfigurationHotkeyEntity? DisableHotkey { get; set; }
|
||||
|
||||
public string ModuleId { get; set; }
|
||||
public string? ModuleId { get; set; }
|
||||
|
||||
public Guid ProfileCategoryId { get; set; }
|
||||
public Guid ProfileId { get; set; }
|
||||
|
||||
public bool FadeInAndOut { get; set; }
|
||||
public int Version { get; set; }
|
||||
}
|
||||
@ -16,7 +16,7 @@ public class ProfileEntity
|
||||
|
||||
public Guid Id { get; set; }
|
||||
|
||||
public string Name { get; set; }
|
||||
public string Name { get; set; } = string.Empty;
|
||||
public bool IsFreshImport { get; set; }
|
||||
|
||||
public List<FolderEntity> Folders { get; set; }
|
||||
@ -28,7 +28,7 @@ public class ProfileEntity
|
||||
Guid oldGuid = Id;
|
||||
Id = guid;
|
||||
|
||||
FolderEntity rootFolder = Folders.FirstOrDefault(f => f.ParentId == oldGuid);
|
||||
FolderEntity? rootFolder = Folders.FirstOrDefault(f => f.ParentId == oldGuid);
|
||||
if (rootFolder != null)
|
||||
rootFolder.ParentId = Id;
|
||||
}
|
||||
|
||||
@ -5,10 +5,10 @@ namespace Artemis.Storage.Entities.Profile;
|
||||
|
||||
public class PropertyEntity
|
||||
{
|
||||
public string Identifier { get; set; }
|
||||
public string Value { get; set; }
|
||||
public string Identifier { get; set; } = string.Empty;
|
||||
public string Value { get; set; } = string.Empty;
|
||||
public bool KeyframesEnabled { get; set; }
|
||||
|
||||
public DataBindingEntity DataBinding { get; set; }
|
||||
public DataBindingEntity? DataBinding { get; set; }
|
||||
public List<KeyframeEntity> KeyframeEntities { get; set; } = new();
|
||||
}
|
||||
@ -4,7 +4,7 @@ namespace Artemis.Storage.Entities.Profile;
|
||||
|
||||
public class PropertyGroupEntity
|
||||
{
|
||||
public string Identifier { get; set; }
|
||||
public string Identifier { get; set; } = string.Empty;
|
||||
public List<PropertyEntity> Properties { get; set; } = new();
|
||||
public List<PropertyGroupEntity> PropertyGroups { get; set; } = new();
|
||||
}
|
||||
@ -11,8 +11,8 @@ public class DeviceEntity
|
||||
Categories = new List<int>();
|
||||
}
|
||||
|
||||
public string Id { get; set; }
|
||||
public string DeviceProvider { get; set; }
|
||||
public string Id { get; set; } = string.Empty;
|
||||
public string DeviceProvider { get; set; } = string.Empty;
|
||||
public float X { get; set; }
|
||||
public float Y { get; set; }
|
||||
public float Rotation { get; set; }
|
||||
@ -24,9 +24,9 @@ public class DeviceEntity
|
||||
public bool IsEnabled { get; set; }
|
||||
|
||||
public int PhysicalLayout { get; set; }
|
||||
public string LogicalLayout { get; set; }
|
||||
public string LayoutType { get; set; }
|
||||
public string LayoutParameter { get; set; }
|
||||
public string? LogicalLayout { get; set; }
|
||||
public string? LayoutType { get; set; }
|
||||
public string? LayoutParameter { get; set; }
|
||||
|
||||
public List<DeviceInputIdentifierEntity> InputIdentifiers { get; set; }
|
||||
public List<InputMappingEntity> InputMappings { get; set; }
|
||||
@ -41,6 +41,6 @@ public class InputMappingEntity
|
||||
|
||||
public class DeviceInputIdentifierEntity
|
||||
{
|
||||
public string InputProvider { get; set; }
|
||||
public object Identifier { get; set; }
|
||||
public string InputProvider { get; set; } = string.Empty;
|
||||
public object Identifier { get; set; } = string.Empty;
|
||||
}
|
||||
@ -10,13 +10,12 @@ public class EntryEntity
|
||||
public long EntryId { get; set; }
|
||||
public int EntryType { get; set; }
|
||||
|
||||
public string Author { get; set; }
|
||||
public string Author { get; set; } = string.Empty;
|
||||
public string Name { get; set; } = string.Empty;
|
||||
public string Summary { get; set; } = string.Empty;
|
||||
|
||||
public long ReleaseId { get; set; }
|
||||
public string ReleaseVersion { get; set; }
|
||||
public string ReleaseVersion { get; set; } = string.Empty;
|
||||
public DateTimeOffset InstalledAt { get; set; }
|
||||
|
||||
public Dictionary<string,object> Metadata { get; set; }
|
||||
public Dictionary<string,object>? Metadata { get; set; }
|
||||
}
|
||||
9
src/Artemis.Storage/Migrations/IProfileMigration.cs
Normal file
9
src/Artemis.Storage/Migrations/IProfileMigration.cs
Normal file
@ -0,0 +1,9 @@
|
||||
using Newtonsoft.Json.Linq;
|
||||
|
||||
namespace Artemis.Storage.Migrations;
|
||||
|
||||
public interface IProfileMigration
|
||||
{
|
||||
int Version { get; }
|
||||
void Migrate(JObject profileJson);
|
||||
}
|
||||
@ -1,6 +1,6 @@
|
||||
using LiteDB;
|
||||
|
||||
namespace Artemis.Storage.Migrations.Interfaces;
|
||||
namespace Artemis.Storage.Migrations;
|
||||
|
||||
public interface IStorageMigration
|
||||
{
|
||||
88
src/Artemis.Storage/Migrations/Profile/M0001NodeProviders.cs
Normal file
88
src/Artemis.Storage/Migrations/Profile/M0001NodeProviders.cs
Normal file
@ -0,0 +1,88 @@
|
||||
using Newtonsoft.Json.Linq;
|
||||
|
||||
namespace Artemis.Storage.Migrations.Profile;
|
||||
|
||||
/// <summary>
|
||||
/// Migrates nodes to be provider-based.
|
||||
/// This requires giving them a ProviderId and updating the their namespaces to match the namespace of the new plugin.
|
||||
/// </summary>
|
||||
internal class M0001NodeProviders : IProfileMigration
|
||||
{
|
||||
/// <inheritdoc />
|
||||
public int Version => 1;
|
||||
|
||||
/// <inheritdoc />
|
||||
public void Migrate(JObject profileJson)
|
||||
{
|
||||
JArray? folders = (JArray?) profileJson["Folders"]?["$values"];
|
||||
JArray? layers = (JArray?) profileJson["Layers"]?["$values"];
|
||||
|
||||
if (folders != null)
|
||||
{
|
||||
foreach (JToken folder in folders)
|
||||
MigrateProfileElement(folder);
|
||||
}
|
||||
|
||||
if (layers != null)
|
||||
{
|
||||
foreach (JToken layer in layers)
|
||||
{
|
||||
MigrateProfileElement(layer);
|
||||
MigratePropertyGroup(layer["GeneralPropertyGroup"]);
|
||||
MigratePropertyGroup(layer["TransformPropertyGroup"]);
|
||||
MigratePropertyGroup(layer["LayerBrush"]?["PropertyGroup"]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void MigrateProfileElement(JToken profileElement)
|
||||
{
|
||||
JArray? layerEffects = (JArray?) profileElement["LayerEffects"]?["$values"];
|
||||
if (layerEffects != null)
|
||||
{
|
||||
foreach (JToken layerEffect in layerEffects)
|
||||
MigratePropertyGroup(layerEffect["PropertyGroup"]);
|
||||
}
|
||||
|
||||
JToken? displayCondition = profileElement["DisplayCondition"];
|
||||
if (displayCondition != null)
|
||||
MigrateNodeScript(displayCondition["Script"]);
|
||||
}
|
||||
|
||||
private void MigratePropertyGroup(JToken? propertyGroup)
|
||||
{
|
||||
if (propertyGroup == null || !propertyGroup.HasValues)
|
||||
return;
|
||||
|
||||
JArray? properties = (JArray?) propertyGroup["Properties"]?["$values"];
|
||||
JArray? propertyGroups = (JArray?) propertyGroup["PropertyGroups"]?["$values"];
|
||||
|
||||
if (properties != null)
|
||||
{
|
||||
foreach (JToken property in properties)
|
||||
MigrateNodeScript(property["DataBinding"]?["NodeScript"]);
|
||||
}
|
||||
|
||||
if (propertyGroups != null)
|
||||
{
|
||||
foreach (JToken childPropertyGroup in propertyGroups)
|
||||
MigratePropertyGroup(childPropertyGroup);
|
||||
}
|
||||
}
|
||||
|
||||
private void MigrateNodeScript(JToken? nodeScript)
|
||||
{
|
||||
if (nodeScript == null || !nodeScript.HasValues)
|
||||
return;
|
||||
|
||||
JArray? nodes = (JArray?) nodeScript["Nodes"]?["$values"];
|
||||
if (nodes == null)
|
||||
return;
|
||||
|
||||
foreach (JToken node in nodes)
|
||||
{
|
||||
node["Type"] = node["Type"]?.Value<string>()?.Replace("Artemis.VisualScripting.Nodes", "Artemis.Plugins.Nodes.General.Nodes");
|
||||
node["ProviderId"] = "Artemis.Plugins.Nodes.General.GeneralNodesProvider-d9e1ee78";
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1,9 +1,8 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using Artemis.Storage.Migrations.Interfaces;
|
||||
using LiteDB;
|
||||
|
||||
namespace Artemis.Storage.Migrations;
|
||||
namespace Artemis.Storage.Migrations.Storage;
|
||||
|
||||
public class M0020AvaloniaReset : IStorageMigration
|
||||
{
|
||||
@ -3,18 +3,17 @@ using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using Artemis.Storage.Entities.Profile;
|
||||
using Artemis.Storage.Entities.Profile.Nodes;
|
||||
using Artemis.Storage.Migrations.Interfaces;
|
||||
using LiteDB;
|
||||
|
||||
namespace Artemis.Storage.Migrations;
|
||||
namespace Artemis.Storage.Migrations.Storage;
|
||||
|
||||
public class M0021GradientNodes : IStorageMigration
|
||||
{
|
||||
private void MigrateDataBinding(PropertyEntity property)
|
||||
{
|
||||
NodeScriptEntity script = property.DataBinding.NodeScript;
|
||||
NodeEntity exitNode = script.Nodes.FirstOrDefault(s => s.IsExitNode);
|
||||
if (exitNode == null)
|
||||
NodeScriptEntity? script = property.DataBinding?.NodeScript;
|
||||
NodeEntity? exitNode = script?.Nodes.FirstOrDefault(s => s.IsExitNode);
|
||||
if (script == null || exitNode == null)
|
||||
return;
|
||||
|
||||
// Create a new node at the same position of the exit node
|
||||
@ -22,7 +21,7 @@ public class M0021GradientNodes : IStorageMigration
|
||||
{
|
||||
Id = Guid.NewGuid(),
|
||||
Type = "ColorGradientNode",
|
||||
PluginId = Guid.Parse("ffffffff-ffff-ffff-ffff-ffffffffffff"),
|
||||
ProviderId = "Artemis.Plugins.Nodes.General.GeneralNodesProvider-d9e1ee78",
|
||||
Name = "Color Gradient",
|
||||
Description = "Outputs a color gradient with the given colors",
|
||||
X = exitNode.X,
|
||||
@ -59,8 +58,11 @@ public class M0021GradientNodes : IStorageMigration
|
||||
exitNode.Y += 30;
|
||||
}
|
||||
|
||||
private void MigrateDataBinding(PropertyGroupEntity propertyGroup)
|
||||
private void MigrateDataBinding(PropertyGroupEntity? propertyGroup)
|
||||
{
|
||||
if (propertyGroup == null)
|
||||
return;
|
||||
|
||||
foreach (PropertyGroupEntity propertyGroupPropertyGroup in propertyGroup.PropertyGroups)
|
||||
MigrateDataBinding(propertyGroupPropertyGroup);
|
||||
|
||||
@ -80,7 +82,7 @@ public class M0021GradientNodes : IStorageMigration
|
||||
foreach (ProfileEntity profileEntity in profiles)
|
||||
{
|
||||
foreach (LayerEntity layer in profileEntity.Layers.Where(le => le.LayerBrush != null))
|
||||
MigrateDataBinding(layer.LayerBrush.PropertyGroup);
|
||||
MigrateDataBinding(layer.LayerBrush?.PropertyGroup);
|
||||
|
||||
repository.Update(profileEntity);
|
||||
}
|
||||
@ -3,14 +3,13 @@ using Artemis.Storage.Entities.Profile;
|
||||
using Artemis.Storage.Entities.Profile.Abstract;
|
||||
using Artemis.Storage.Entities.Profile.Conditions;
|
||||
using Artemis.Storage.Entities.Profile.Nodes;
|
||||
using Artemis.Storage.Migrations.Interfaces;
|
||||
using LiteDB;
|
||||
|
||||
namespace Artemis.Storage.Migrations;
|
||||
namespace Artemis.Storage.Migrations.Storage;
|
||||
|
||||
public class M0022TransitionNodes : IStorageMigration
|
||||
{
|
||||
private void MigrateNodeScript(NodeScriptEntity nodeScript)
|
||||
private void MigrateNodeScript(NodeScriptEntity? nodeScript)
|
||||
{
|
||||
if (nodeScript == null)
|
||||
return;
|
||||
@ -28,7 +27,7 @@ public class M0022TransitionNodes : IStorageMigration
|
||||
}
|
||||
}
|
||||
|
||||
private void MigratePropertyGroup(PropertyGroupEntity propertyGroup)
|
||||
private void MigratePropertyGroup(PropertyGroupEntity? propertyGroup)
|
||||
{
|
||||
if (propertyGroup == null)
|
||||
return;
|
||||
@ -39,7 +38,7 @@ public class M0022TransitionNodes : IStorageMigration
|
||||
MigrateNodeScript(property.DataBinding?.NodeScript);
|
||||
}
|
||||
|
||||
private void MigrateDisplayCondition(IConditionEntity conditionEntity)
|
||||
private void MigrateDisplayCondition(IConditionEntity? conditionEntity)
|
||||
{
|
||||
if (conditionEntity is EventConditionEntity eventConditionEntity)
|
||||
MigrateNodeScript(eventConditionEntity.Script);
|
||||
@ -70,14 +69,14 @@ public class M0022TransitionNodes : IStorageMigration
|
||||
MigratePropertyGroup(layer.GeneralPropertyGroup);
|
||||
MigratePropertyGroup(layer.TransformPropertyGroup);
|
||||
foreach (LayerEffectEntity layerEffectEntity in layer.LayerEffects)
|
||||
MigratePropertyGroup(layerEffectEntity?.PropertyGroup);
|
||||
MigratePropertyGroup(layerEffectEntity.PropertyGroup);
|
||||
MigrateDisplayCondition(layer.DisplayCondition);
|
||||
}
|
||||
|
||||
foreach (FolderEntity folder in profileEntity.Folders)
|
||||
{
|
||||
foreach (LayerEffectEntity folderLayerEffect in folder.LayerEffects)
|
||||
MigratePropertyGroup(folderLayerEffect?.PropertyGroup);
|
||||
MigratePropertyGroup(folderLayerEffect.PropertyGroup);
|
||||
MigrateDisplayCondition(folder.DisplayCondition);
|
||||
}
|
||||
|
||||
@ -1,8 +1,7 @@
|
||||
using System.Collections.Generic;
|
||||
using Artemis.Storage.Migrations.Interfaces;
|
||||
using LiteDB;
|
||||
|
||||
namespace Artemis.Storage.Migrations;
|
||||
namespace Artemis.Storage.Migrations.Storage;
|
||||
|
||||
public class M0023LayoutProviders : IStorageMigration
|
||||
{
|
||||
100
src/Artemis.Storage/Migrations/Storage/M0024NodeProviders.cs
Normal file
100
src/Artemis.Storage/Migrations/Storage/M0024NodeProviders.cs
Normal file
@ -0,0 +1,100 @@
|
||||
using System.Collections.Generic;
|
||||
using Artemis.Storage.Entities.Profile;
|
||||
using LiteDB;
|
||||
|
||||
namespace Artemis.Storage.Migrations.Storage;
|
||||
|
||||
public class M0024NodeProviders : IStorageMigration
|
||||
{
|
||||
public int UserVersion => 24;
|
||||
|
||||
public void Apply(LiteRepository repository)
|
||||
{
|
||||
List<ProfileCategoryEntity> profileCategories = repository.Query<ProfileCategoryEntity>().ToList();
|
||||
foreach (ProfileCategoryEntity profileCategory in profileCategories)
|
||||
{
|
||||
foreach (ProfileConfigurationEntity profileConfigurationEntity in profileCategory.ProfileConfigurations)
|
||||
{
|
||||
profileConfigurationEntity.Version = 1;
|
||||
}
|
||||
repository.Update(profileCategory);
|
||||
}
|
||||
|
||||
ILiteCollection<BsonDocument> collection = repository.Database.GetCollection("ProfileEntity");
|
||||
foreach (BsonDocument profileBson in collection.FindAll())
|
||||
{
|
||||
BsonArray? folders = profileBson["Folders"]?.AsArray;
|
||||
BsonArray? layers = profileBson["Layers"]?.AsArray;
|
||||
|
||||
if (folders != null)
|
||||
{
|
||||
foreach (BsonValue folder in folders)
|
||||
MigrateProfileElement(folder.AsDocument);
|
||||
}
|
||||
|
||||
if (layers != null)
|
||||
{
|
||||
foreach (BsonValue layer in layers)
|
||||
{
|
||||
MigrateProfileElement(layer.AsDocument);
|
||||
MigratePropertyGroup(layer.AsDocument["GeneralPropertyGroup"].AsDocument);
|
||||
MigratePropertyGroup(layer.AsDocument["TransformPropertyGroup"].AsDocument);
|
||||
MigratePropertyGroup(layer.AsDocument["LayerBrush"]?["PropertyGroup"].AsDocument);
|
||||
}
|
||||
}
|
||||
|
||||
collection.Update(profileBson);
|
||||
}
|
||||
}
|
||||
|
||||
private void MigrateProfileElement(BsonDocument profileElement)
|
||||
{
|
||||
BsonArray? layerEffects = profileElement["LayerEffects"]?.AsArray;
|
||||
if (layerEffects != null)
|
||||
{
|
||||
foreach (BsonValue layerEffect in layerEffects)
|
||||
MigratePropertyGroup(layerEffect.AsDocument["PropertyGroup"].AsDocument);
|
||||
}
|
||||
|
||||
BsonValue? displayCondition = profileElement["DisplayCondition"];
|
||||
if (displayCondition != null)
|
||||
MigrateNodeScript(displayCondition.AsDocument["Script"].AsDocument);
|
||||
}
|
||||
|
||||
private void MigratePropertyGroup(BsonDocument? propertyGroup)
|
||||
{
|
||||
if (propertyGroup == null || propertyGroup.Keys.Count == 0)
|
||||
return;
|
||||
|
||||
BsonArray? properties = propertyGroup["Properties"]?.AsArray;
|
||||
BsonArray? propertyGroups = propertyGroup["PropertyGroups"]?.AsArray;
|
||||
|
||||
if (properties != null)
|
||||
{
|
||||
foreach (BsonValue property in properties)
|
||||
MigrateNodeScript(property.AsDocument["DataBinding"]?["NodeScript"]?.AsDocument);
|
||||
}
|
||||
|
||||
if (propertyGroups != null)
|
||||
{
|
||||
foreach (BsonValue childPropertyGroup in propertyGroups)
|
||||
MigratePropertyGroup(childPropertyGroup.AsDocument);
|
||||
}
|
||||
}
|
||||
|
||||
private void MigrateNodeScript(BsonDocument? nodeScript)
|
||||
{
|
||||
if (nodeScript == null || nodeScript.Keys.Count == 0)
|
||||
return;
|
||||
|
||||
BsonArray? nodes = nodeScript["Nodes"]?.AsArray;
|
||||
if (nodes == null)
|
||||
return;
|
||||
|
||||
foreach (BsonValue node in nodes)
|
||||
{
|
||||
node.AsDocument["Type"] = node.AsDocument["Type"]?.AsString?.Replace("Artemis.VisualScripting.Nodes", "Artemis.Plugins.Nodes.General.Nodes");
|
||||
node.AsDocument["ProviderId"] = "Artemis.Plugins.Nodes.General.GeneralNodesProvider-d9e1ee78";
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -25,7 +25,7 @@ internal class DeviceRepository : IDeviceRepository
|
||||
_repository.Delete<DeviceEntity>(deviceEntity.Id);
|
||||
}
|
||||
|
||||
public DeviceEntity Get(string id)
|
||||
public DeviceEntity? Get(string id)
|
||||
{
|
||||
return _repository.FirstOrDefault<DeviceEntity>(s => s.Id == id);
|
||||
}
|
||||
|
||||
@ -27,12 +27,12 @@ internal class EntryRepository : IEntryRepository
|
||||
_repository.Delete<EntryEntity>(entryEntity.Id);
|
||||
}
|
||||
|
||||
public EntryEntity Get(Guid id)
|
||||
public EntryEntity? Get(Guid id)
|
||||
{
|
||||
return _repository.FirstOrDefault<EntryEntity>(s => s.Id == id);
|
||||
}
|
||||
|
||||
public EntryEntity GetByEntryId(long entryId)
|
||||
public EntryEntity? GetByEntryId(long entryId)
|
||||
{
|
||||
return _repository.FirstOrDefault<EntryEntity>(s => s.EntryId == entryId);
|
||||
}
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Loading…
x
Reference in New Issue
Block a user