First commit

This commit is contained in:
Gilles Lazures 2026-01-30 14:33:21 +01:00
parent 15277cf8eb
commit 861cbbe23c
10 changed files with 324 additions and 1 deletions

60
.gitignore vendored Normal file
View File

@ -0,0 +1,60 @@
## A streamlined .gitignore for modern .NET projects
## including temporary files, build results, and
## files generated by popular .NET tools. If you are
## developing with Visual Studio, the VS .gitignore
## https://github.com/github/gitignore/blob/main/VisualStudio.gitignore
## has more thorough IDE-specific entries.
##
## Get latest from https://github.com/github/gitignore/blob/main/Dotnet.gitignore
# Build results
[Dd]ebug/
[Dd]ebugPublic/
[Rr]elease/
[Rr]eleases/
x64/
x86/
[Ww][Ii][Nn]32/
[Aa][Rr][Mm]/
[Aa][Rr][Mm]64/
bld/
[Bb]in/
[Oo]bj/
[Ll]og/
[Ll]ogs/
# .NET Core
project.lock.json
project.fragment.lock.json
artifacts/
# ASP.NET Scaffolding
ScaffoldingReadMe.txt
# NuGet Packages
*.nupkg
# NuGet Symbol Packages
*.snupkg
# dotenv environment variables file
.env
# Others
~$*
*~
CodeCoverage/
# MSBuild Binary and Structured Log
*.binlog
# MSTest test Results
[Tt]est[Rr]esult*/
[Bb]uild[Ll]og.*
# NUnit
*.VisualState.xml
TestResult.xml
nunit-*.xml
temp
nuget.config

View File

@ -0,0 +1,25 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>net8.0</TargetFramework>
<Platforms>AnyCPU</Platforms>
<RootNamespace>Photino_Boilerplate</RootNamespace>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
<PublishTrimmed>false</PublishTrimmed>
</PropertyGroup>
<Target Name="PackRenderer" BeforeTargets="DispatchToInnerBuild;BeforeBuild">
<PropertyGroup>
<BrikPackagerDll>$([System.IO.Path]::Combine('$(PkgBrikPackager)', 'lib', 'net8.0', 'BrikPackager.dll'))</BrikPackagerDll>
<InputPath>$([System.IO.Path]::Combine('$(MSBuildProjectDirectory)', 'src', 'resources', 'renderer'))</InputPath>
<OutputPathFile>$([System.IO.Path]::Combine('$(TargetDir)', 'root.dat'))</OutputPathFile>
</PropertyGroup>
<Message Importance="high" Text="[] Packaging renderer (Cross-Platform)..." />
<Exec Command="dotnet &quot;$(BrikPackagerDll)&quot; --action pack --input &quot;$(InputPath)&quot; --output &quot;$(OutputPathFile)&quot; --key 66" />
<Message Importance="high" Text="[] Renderer packed at: $(OutputPathFile)" />
</Target>
<ItemGroup>
<PackageReference Include="BrikPackager" Version="0.0.1" GeneratePathProperty="true" />
<PackageReference Include="Photino.NET" Version="4.0.16" />
</ItemGroup>
</Project>

24
Photino-Boilerplate.sln Normal file
View File

@ -0,0 +1,24 @@
Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio Version 17
VisualStudioVersion = 17.5.2.0
MinimumVisualStudioVersion = 10.0.40219.1
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Photino-Boilerplate", "Photino-Boilerplate.csproj", "{5FF73963-D009-62ED-7350-FF17EC625A26}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Release|Any CPU = Release|Any CPU
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{5FF73963-D009-62ED-7350-FF17EC625A26}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{5FF73963-D009-62ED-7350-FF17EC625A26}.Debug|Any CPU.Build.0 = Debug|Any CPU
{5FF73963-D009-62ED-7350-FF17EC625A26}.Release|Any CPU.ActiveCfg = Release|Any CPU
{5FF73963-D009-62ED-7350-FF17EC625A26}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {5D254170-B473-471E-AD56-26A8F4C4189E}
EndGlobalSection
EndGlobal

View File

@ -1,2 +1,2 @@
# PhotinoBase
# Photino-Boilerplate

78
src/main/Program.cs Normal file
View File

@ -0,0 +1,78 @@
using System.Reflection;
using System.Text.Json;
using BrikPackager;
using PhotinoBoilerplate.Utils;
using Photino.NET;
namespace PhotinoBoilerplate;
class Program{
public static readonly JsonSerializerOptions _jsonOptions = new() { PropertyNamingPolicy = JsonNamingPolicy.CamelCase };
private static readonly string __dirname = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location)!;
[STAThread]
static void Main(string[] args) {
CreateMainWindow().WaitForClose();
}
public static PhotinoWindow CreateMainWindow() {
BrikPackage bpkg = new BrikPackage(Path.Combine(__dirname, "root.dat"), 66);
List<string> entries = bpkg.ListEntries();
var window = new PhotinoWindow()
.SetTitle("Photino Boilerplate")
.SetUseOsDefaultLocation(false)
.SetUseOsDefaultSize(false)
.RegisterCustomSchemeHandler("http", (object sender, string scheme, string url, out string contentType) =>{
Uri uri = new Uri(url);
switch (uri.Host){
case "internal":
string internalPath = uri.AbsolutePath;
contentType = MimeHelper.GetMimeType(uri.AbsolutePath);
byte[] fileData = bpkg.GetFileBytes(internalPath.TrimStart('/'));
return fileData != null ? new MemoryStream(fileData) : null;
default:
contentType = null!;
return null;
}
});
window.WindowCreated += (sender, e) => {
SetupBridge(window);
WindowHelper.setSize(window, 900, 600);
window.Center();
};
window.Load("http://internal/index.html");
return window;
}
public static void SetupBridge(PhotinoWindow window) {
window.RegisterWebMessageReceivedHandler(async (object? sender, string message) => {
try {
var json = JsonDocument.Parse(message);
string requestId = json.RootElement.GetProperty("requestId").GetString()!;
string method = json.RootElement.GetProperty("functionName").GetString()!;
var jsonPayload = json.RootElement.GetProperty("payload");
var pw = (PhotinoWindow)sender!;
object? payload = null;
switch (method) {
case "hello::world":
payload = "Hello from C#";
break;
}
var response = new { requestId, payload };
window.SendWebMessage(JsonSerializer.Serialize(response, _jsonOptions));
} catch (Exception ex) {
Console.WriteLine($"Error stacktrace: {ex.StackTrace}");
Console.WriteLine($"Bridge error: {ex.Message}");
}
});
}
}

View File

@ -0,0 +1,29 @@
using Photino.NET;
using System.Drawing;
namespace PhotinoBoilerplate.Utils;
public static class WindowHelper {
private const float StandardDpi = 96.0f;
public static Size GetScaledSize(PhotinoWindow window, int logicalWidth, int logicalHeight) {
float currentDpi = window.ScreenDpi > 0 ? window.ScreenDpi : StandardDpi;
float scaleFactor = currentDpi / StandardDpi;
return new Size(
(int)(logicalWidth * scaleFactor),
(int)(logicalHeight * scaleFactor)
);
}
public static void setSize(PhotinoWindow window, int width, int height) {
Size targetSize = GetScaledSize(window, width, height);
window
.SetResizable(true)
.SetSize(targetSize)
.SetMinSize(targetSize.Width, targetSize.Height);
}
}

View File

@ -0,0 +1,45 @@
@import url("https://fonts.googleapis.com/css2?family=Poppins:ital,wght@0,100;0,200;0,300;0,400;0,500;0,600;0,700;0,800;0,900;1,100;1,200;1,300;1,400;1,500;1,600;1,700;1,800;1,900&display=swap");
* {
margin: 0px;
padding: 0px;
box-sizing: border-box;
}
main {
display: flex;
position: absolute;
top: 0px;
left: 0px;
right: 0px;
bottom: 0px;
flex-wrap: wrap;
flex-direction: column;
gap: 10px;
color: #cecece;
background-color: #404551;
align-items: center;
justify-content: center;
font-family: "Poppins", sans-serif;
}
button {
cursor: pointer;
padding: 7px 7px 7px 7px;
color: #cecece;
font-weight: 500;
border: none;
outline: none;
border-radius: 5px;
background-color: #c8850a;
transition: .3s all;
font-family: "Poppins", sans-serif;
}
button:hover {
filter: brightness(0.95);
}
button:active {
filter: brightness(1.10);
}

View File

@ -0,0 +1,4 @@
async function callCSharp() {
const result = await system.call("hello::world")
alert(result)
}

View File

@ -0,0 +1,34 @@
const system = {
_pendingRequests: new Map(),
init: function() {
window.external.receiveMessage(response => {
try {
const res = JSON.parse(response)
if (res.requestId && this._pendingRequests.has(res.requestId)) {
const { resolve } = this._pendingRequests.get(res.requestId)
this._pendingRequests.delete(res.requestId)
resolve(res.payload)
}
} catch (e) {
console.error("Erreur format message :", e)
}
})
},
call: function(functionName, data = {}) {
return new Promise((resolve, reject) => {
const requestId = Math.random().toString(36).substring(7)
this._pendingRequests.set(requestId, { resolve, reject })
window.external.sendMessage(JSON.stringify({
requestId: requestId,
functionName: functionName,
payload: data
}))
})
}
}
system.init()

View File

@ -0,0 +1,24 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<link rel="stylesheet" href="./assets/css/index.css">
<title></title>
</head>
<body>
<main>
<h2>
Bienvenue dans Photino
</h2>
<button onclick="callCSharp()">
Appellez une fonction C#
</button>
</main>
<script src="./assets/js/ipc.js"></script>
<script src="./assets/js/index.js"></script>
</body>
</html>