Skip to content
This repository was archived by the owner on Sep 15, 2025. It is now read-only.

Commit 6692bbc

Browse files
committed
More settings, fixes, and improvements
Removed AForge dependency, created and added a simpler solution (MjpegClient) Removed MjpegStreamManager (reworked to CameraStreamManager and will be used for other stream types) Added DebugMode to config (show/hide the console window) Added AlwaysOnTop to config (always appear above other windows) WebUI properly supports custom camera URL (should support any protocol that works in the browser but needs testing) Reworked a bunch of logic for the WebUI, moving to a WebSocket Misc bug fixes
1 parent 856d099 commit 6692bbc

20 files changed

Lines changed: 1257 additions & 692 deletions

FlashForgeUI.csproj

Lines changed: 3 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -34,18 +34,6 @@
3434
<WarningLevel>4</WarningLevel>
3535
</PropertyGroup>
3636
<ItemGroup>
37-
<Reference Include="AForge, Version=2.2.5.0, Culture=neutral, PublicKeyToken=c1db6ff4eaa06aeb, processorArchitecture=MSIL">
38-
<HintPath>packages\AForge.2.2.5\lib\AForge.dll</HintPath>
39-
</Reference>
40-
<Reference Include="AForge.Imaging, Version=2.2.5.0, Culture=neutral, PublicKeyToken=ba8ddea9676ca48b, processorArchitecture=MSIL">
41-
<HintPath>packages\AForge.Imaging.2.2.5\lib\AForge.Imaging.dll</HintPath>
42-
</Reference>
43-
<Reference Include="AForge.Math, Version=2.2.5.0, Culture=neutral, PublicKeyToken=abba2e25397ee8c9, processorArchitecture=MSIL">
44-
<HintPath>packages\AForge.Math.2.2.5\lib\AForge.Math.dll</HintPath>
45-
</Reference>
46-
<Reference Include="AForge.Video, Version=2.2.5.0, Culture=neutral, PublicKeyToken=cbfb6e07d173c401, processorArchitecture=MSIL">
47-
<HintPath>packages\AForge.Video.2.2.5\lib\AForge.Video.dll</HintPath>
48-
</Reference>
4937
<Reference Include="Costura, Version=6.0.0.0, Culture=neutral, PublicKeyToken=9919ef960d84173d, processorArchitecture=MSIL">
5038
<HintPath>packages\Costura.Fody.6.0.0\lib\netstandard2.0\Costura.dll</HintPath>
5139
</Reference>
@@ -115,10 +103,11 @@
115103
<DependentUpon>MainMenu.cs</DependentUpon>
116104
</Compile>
117105
<Compile Include="ui\main\manager\ButtonManager.cs" />
106+
<Compile Include="ui\main\manager\CameraStreamManager.cs" />
118107
<Compile Include="ui\main\manager\ConnectionManager.cs" />
119-
<Compile Include="ui\main\manager\MjpegStreamManager.cs" />
120108
<Compile Include="ui\main\manager\StatusTimerManager.cs" />
121109
<Compile Include="ui\main\util\Compat.cs" />
110+
<Compile Include="ui\main\util\MjpegClient.cs" />
122111
<Compile Include="ui\main\util\UiHelper.cs" />
123112
<Compile Include="ui\window\PrinterPairingWindow.cs">
124113
<SubType>Form</SubType>
@@ -158,6 +147,7 @@
158147
</Compile>
159148
<Compile Include="webui\PrinterWebServer.cs" />
160149
<Compile Include="webui\WebServerBridge.cs" />
150+
<Compile Include="webui\WebSocketHandler.cs" />
161151
<EmbeddedResource Include="Properties\Resources.resx">
162152
<Generator>ResXFileCodeGenerator</Generator>
163153
<LastGenOutput>Resources.Designer.cs</LastGenOutput>

packages.config

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,5 @@
11
<?xml version="1.0" encoding="utf-8"?>
22
<packages>
3-
<package id="AForge" version="2.2.5" targetFramework="net48" />
4-
<package id="AForge.Imaging" version="2.2.5" targetFramework="net48" />
5-
<package id="AForge.Math" version="2.2.5" targetFramework="net48" />
6-
<package id="AForge.Video" version="2.2.5" targetFramework="net48" />
73
<package id="Costura.Fody" version="6.0.0" targetFramework="net48" developmentDependency="true" />
84
<package id="Discord.Webhook" version="1.0.9" targetFramework="net48" />
95
<package id="Fody" version="6.9.1" targetFramework="net48" developmentDependency="true" />

program/Program.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,15 +11,15 @@ namespace FlashForgeUI
1111
static class Program
1212
{
1313
[DllImport("kernel32.dll")]
14-
private static extern bool AllocConsole();
14+
public static extern bool AllocConsole();
1515

1616
/// <summary>
1717
/// The main entry point for the application.
1818
/// </summary>
1919
[STAThread]
2020
static void Main()
2121
{
22-
AllocConsole();
22+
//AllocConsole();
2323
Application.EnableVisualStyles();
2424
Application.SetCompatibleTextRenderingDefault(false);
2525
Application.Run(new ui.main.MainMenu());

program/util/Config.cs

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
1-
using System.Diagnostics;
1+
using System.ComponentModel;
2+
using System.Diagnostics;
23
using System.IO;
34
using System.Runtime.InteropServices;
45
using Newtonsoft.Json;
@@ -10,6 +11,16 @@ public class Config
1011

1112
public bool WebUi { get; set; }
1213
public bool DiscordSync { get; set; }
14+
15+
[JsonProperty(DefaultValueHandling = DefaultValueHandling.Populate)]
16+
[DefaultValue(false)]
17+
public bool AlwaysOnTop { get; set; }
18+
19+
20+
[JsonProperty(DefaultValueHandling = DefaultValueHandling.Populate)]
21+
[DefaultValue(false)]
22+
public bool DebugMode { get; set; }
23+
1324
public string WebhookUrl { get; set; }
1425

1526
public bool CustomCamera { get; set; }
@@ -31,6 +42,8 @@ public Config Load()
3142
Debug.WriteLine("config.json not found, creating & loading default settings.");
3243
WebUi = false;
3344
DiscordSync = false;
45+
AlwaysOnTop = false;
46+
DebugMode = false;
3447
WebhookUrl = "";
3548
CustomCamera = false;
3649
CustomCameraUrl = "";

program/util/WebhookHelper.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -79,7 +79,7 @@ private async Task<Embed> CreatePrinterStatusEmbed(FiveMClient printerClient)
7979

8080
var embed = new EmbedBuilder().WithTitle(printerClient.PrinterName + " status").WithColor(Colors.Orange);
8181

82-
var img = await mainMenu.GetMjpegStreamManager().GetSingleFrameAsync();
82+
var img = await mainMenu.GetCameraStreamManager().GetSingleFrameAsync();
8383

8484

8585
var webcamPreview = await ImgBB.Upload(img, "preview.png");

ui/main/MainMenu.cs

Lines changed: 52 additions & 51 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
using System.Threading;
88
using System.Threading.Tasks;
99
using System.Windows.Forms;
10-
using AForge.Video;
10+
1111
using FiveMApi.api;
1212
using FlashForgeUI.manager;
1313
using FlashForgeUI.program.util;
@@ -24,7 +24,7 @@ public partial class MainMenu : Form
2424
// and theme accordingly if we cannot get the scroll to bottom to work
2525
// it does look nicer though.
2626

27-
internal MJPEGStream mjpegStream;
27+
//internal MJPEGStream mjpegStream;
2828

2929
public FiveMClient printerClient;
3030

@@ -37,17 +37,19 @@ public partial class MainMenu : Form
3737

3838
// Managers
3939
private ConnectionManager _connectionManager;
40-
internal MjpegStreamManager StreamManager;
40+
internal CameraStreamManager StreamManager;
4141
private StatusTimerManager _statusTimerManager;
42-
private ButtonManager _buttonManager;
42+
internal ButtonManager ButtonManager;
43+
44+
private UiHelper _uiHelper;
4345

4446

45-
public MjpegStreamManager GetMjpegStreamManager()
47+
public CameraStreamManager GetCameraStreamManager()
4648
{ // for WebhookHelper (sending preview image to discord)
4749
return StreamManager;
4850
}
4951

50-
internal bool isConnected = false;
52+
internal bool IsConnected;
5153
internal bool WebcamOn;
5254

5355
public MainMenu()
@@ -56,7 +58,8 @@ public MainMenu()
5658

5759
// hook form events
5860
Shown += MainMenu_Shown;
59-
Closing += MainMenu_Closing;
61+
//Closing += MainMenu_Closing;
62+
FormClosing += MainMenu_Closing;
6063

6164
// hook timer events
6265
timerStatusUpdate.Tick += timerStatusUpdate_Tick;
@@ -75,15 +78,14 @@ private void InitWebhook()
7578
webhook = new WebhookHelper(config.WebhookUrl, this);
7679
}
7780

78-
private async Task StartTimers()
81+
private void StartTimers()
7982
{
8083
timerStatusUpdate_Tick(null, null); // 'kick start' before first timer elapses
8184
timerSyncInfo_Tick(null, null);
8285
timerStatusUpdate.Start();
8386
timerSyncInfo.Start();
8487
if (config.DiscordSync) timerSyncDiscord.Start();
85-
// todo better way to check for webcam availability
86-
if (await printerClient.Info.IsPrinting() && printerClient.IsPro) {
88+
if (printerClient.IsPro || config.CustomCamera && !string.IsNullOrEmpty(config.CustomCameraUrl)) {
8789
StreamManager.Start();
8890
WebcamOn = true;
8991
toggleWebcamButton.Text = "Preview off";
@@ -92,7 +94,7 @@ private async Task StartTimers()
9294

9395
private void StartWebUi()
9496
{
95-
webServer = new PrinterWebServer(this);
97+
webServer = new PrinterWebServer(this, config);
9698
webServer.Start();
9799
}
98100

@@ -320,18 +322,23 @@ public dynamic GetPrinterStatus()
320322

321323
internal async void MainMenu_Shown(object sender, EventArgs e)
322324
{
325+
// load config
326+
config = new Config().Load();
327+
328+
_uiHelper = new UiHelper(this);
329+
if (config.AlwaysOnTop) _uiHelper.SetOnTop();
330+
323331
// init managers
324-
// todo all of these have to be updated or refactored to use this
325-
// they are expecting the old UI (Form1.cs)
326332
_connectionManager = new ConnectionManager(this);
327-
StreamManager = new MjpegStreamManager(this);
328-
_statusTimerManager = new StatusTimerManager(this);
329-
_buttonManager = new ButtonManager(this);
333+
StreamManager = new CameraStreamManager(this);
334+
_statusTimerManager = new StatusTimerManager(this, _uiHelper);
335+
ButtonManager = new ButtonManager(this);
330336

331-
// load config
332-
config = new Config().Load();
337+
338+
// only show console window if in debug mode
339+
if (config.DebugMode) Program.AllocConsole();
333340

334-
isConnected = await Connect();
341+
IsConnected = await Connect();
335342
}
336343

337344
internal async Task<bool> Connect()
@@ -345,7 +352,7 @@ internal async Task<bool> Connect()
345352
CheckFeatures();
346353

347354
if (config.DiscordSync) InitWebhook(); // only check/enable the webhook if the user actually enabled it.
348-
await StartTimers();
355+
StartTimers();
349356
if (config.WebUi) StartWebUi();
350357

351358
return true;
@@ -356,45 +363,32 @@ internal async Task<bool> Connect()
356363

357364
internal void MainMenu_Closing(object sender, CancelEventArgs cancelEventArgs)
358365
{
359-
// shutdown Web UI
360-
if (config.WebUi) webServer.Stop();
361-
try
362-
{
363-
timerStatusUpdate.Stop(); // stop requesting status updates from printer
364-
timerSyncInfo.Stop();
365-
StreamManager.Stop(); // dispose of webcam stream
366-
printerClient.Dispose(); // end TcpClient control, shutdown keep alive
367-
printerClient = null;
368-
}
369-
catch
370-
{
371-
// not ideal but
372-
}
366+
Application.Exit();
373367
}
374368

375369
private async void ledOnButton_Click(object sender, EventArgs e)
376370
{
377-
await _buttonManager.LedOn();
371+
await ButtonManager.LedOn();
378372
}
379373

380374
private async void ledOffButton_Click(object sender, EventArgs e)
381375
{
382-
await _buttonManager.LedOff();
376+
await ButtonManager.LedOff();
383377
}
384378

385379
private async void pauseJobButton_Click(object sender, EventArgs e)
386380
{
387-
await _buttonManager.PauseJob();
381+
await ButtonManager.PauseJob();
388382
}
389383

390384
private async void resumeJobButton_Click(object sender, EventArgs e)
391385
{
392-
await _buttonManager.ResumeJob();
386+
await ButtonManager.ResumeJob();
393387
}
394388

395389
private async void stopJobButton_Click(object sender, EventArgs e)
396390
{
397-
await _buttonManager.StopJob();
391+
await ButtonManager.StopJob();
398392
}
399393

400394
private async void swapFilamentButton_Click(object sender, EventArgs e)
@@ -421,19 +415,19 @@ private async void homeAxesButton_Click(object sender, EventArgs e)
421415
private async void uploadJobButton_Click(object sender, EventArgs e)
422416
{
423417
if (!await CheckJobReady()) return; // make sure the printer is ready for a new job
424-
if (!await _buttonManager.SelectAndUploadGCodeFile()) AppendLog("Uploading new job cancelled.");
418+
if (!await ButtonManager.SelectAndUploadGCodeFile()) AppendLog("Uploading new job cancelled.");
425419
}
426420

427421
private async void startRecentJobButton_Click(object sender, EventArgs e)
428422
{
429423
if (!await CheckJobReady()) return;
430-
await _buttonManager.SelectRecentJob();
424+
await ButtonManager.SelectRecentJob();
431425
}
432426

433427
private async void startLocalJobButton_Click(object sender, EventArgs e)
434428
{
435429
if (!await CheckJobReady()) return;
436-
await _buttonManager.SelectLocalJob();
430+
await ButtonManager.SelectLocalJob();
437431
}
438432

439433
private void sendCmdButton_Click(object sender, EventArgs e)
@@ -443,7 +437,7 @@ private void sendCmdButton_Click(object sender, EventArgs e)
443437

444438
private void toggleWebcamButton_Click(object sender, EventArgs e)
445439
{
446-
_buttonManager.TogglePreview();
440+
ButtonManager.TogglePreview();
447441
}
448442

449443
private async void setBedTempButton_Click(object sender, EventArgs e)
@@ -528,27 +522,27 @@ private async void disableExtruderHeatButton_Click(object sender, EventArgs e)
528522

529523
private async void externalFiltrationButton_Click(object sender, EventArgs e)
530524
{
531-
await _buttonManager.ExternalFilterOn();
525+
await ButtonManager.ExternalFilterOn();
532526
}
533527

534528
private async void internalFiltrationButton_Click(object sender, EventArgs e)
535529
{
536-
await _buttonManager.InternalFilterOn();
530+
await ButtonManager.InternalFilterOn();
537531
}
538532

539533
private async void disableFiltrationButton_Click(object sender, EventArgs e)
540534
{
541-
await _buttonManager.FilteringOff();
535+
await ButtonManager.FilteringOff();
542536
}
543537

544538
private async void setCoolingFanButton_Click(object sender, EventArgs e)
545539
{
546-
await _buttonManager.SetCoolingFanSpeed();
540+
await ButtonManager.SetCoolingFanSpeed();
547541
}
548542

549543
private async void setChamberFanButton_Click(object sender, EventArgs e)
550544
{
551-
await _buttonManager.SetChamberFanSpeed();
545+
await ButtonManager.SetChamberFanSpeed();
552546
}
553547

554548
private async void setSpeedOffsetButton_Click(object sender, EventArgs e)
@@ -563,17 +557,24 @@ private async void setZaxisOffsetButton_Click(object sender, EventArgs e)
563557

564558
private async void clearPlatformButton_Click(object sender, EventArgs e)
565559
{
566-
await _buttonManager.ClearPlatform();
560+
await ButtonManager.ClearPlatform();
567561
}
568562

569563
private void settingsButton_Click(object sender, EventArgs e)
570564
{
571-
_buttonManager.OpenSettings();
565+
ButtonManager.OpenSettings();
572566
}
573567

568+
// todo disconnect button?
569+
574570
private async void connectButton_Click(object sender, EventArgs e)
575571
{
576-
isConnected = await Connect();
572+
if (IsConnected)
573+
{
574+
MessageBox.Show("You're already connected to a printer!", "Already connected!");
575+
return;
576+
}
577+
IsConnected = await Connect();
577578
}
578579
}
579580
}

0 commit comments

Comments
 (0)