mirror of
https://github.com/Leonmmcoset/CMLeonOS.git
synced 2026-04-21 19:24:00 +00:00
Paint增加保存,重写StartMenu的UI,修复部分渲染bug
This commit is contained in:
@@ -15,9 +15,13 @@
|
||||
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
using Cosmos.System;
|
||||
using Cosmos.System.Graphics;
|
||||
using CMLeonOS;
|
||||
using CMLeonOS.Gui.UILib;
|
||||
using CMLeonOS.Utils;
|
||||
using System;
|
||||
using System.Drawing;
|
||||
using System.IO;
|
||||
|
||||
namespace CMLeonOS.Gui.Apps.Paint
|
||||
{
|
||||
@@ -30,14 +34,24 @@ namespace CMLeonOS.Gui.Apps.Paint
|
||||
AppWindow window;
|
||||
|
||||
Window canvas;
|
||||
Button openButton;
|
||||
Button saveButton;
|
||||
Button saveAsButton;
|
||||
|
||||
ToolBox toolBox;
|
||||
|
||||
ColourPicker colourPicker;
|
||||
FileBrowser fileBrowser;
|
||||
|
||||
WindowManager wm = ProcessManager.GetProcess<WindowManager>();
|
||||
|
||||
private bool down = false;
|
||||
private const int sidePanelWidth = 128;
|
||||
private const int topBarHeight = 40;
|
||||
private const int topButtonWidth = 84;
|
||||
private const int topButtonHeight = 24;
|
||||
private const int topButtonGap = 8;
|
||||
private string currentFilePath = string.Empty;
|
||||
|
||||
internal Color SelectedColor { get; set; } = Color.Black;
|
||||
|
||||
@@ -54,6 +68,190 @@ namespace CMLeonOS.Gui.Apps.Paint
|
||||
down = true;
|
||||
}
|
||||
|
||||
private void ShowMessage(string title, string text)
|
||||
{
|
||||
MessageBox messageBox = new MessageBox(this, title, text);
|
||||
messageBox.Show();
|
||||
}
|
||||
|
||||
private void Relayout()
|
||||
{
|
||||
toolBox.MoveAndResize(0, 0, sidePanelWidth, window.Height);
|
||||
colourPicker.MoveAndResize(window.Width - sidePanelWidth, 0, sidePanelWidth, window.Height);
|
||||
|
||||
int buttonsX = sidePanelWidth + 12;
|
||||
openButton.MoveAndResize(buttonsX, 8, topButtonWidth, topButtonHeight);
|
||||
saveButton.MoveAndResize(buttonsX + topButtonWidth + topButtonGap, 8, topButtonWidth, topButtonHeight);
|
||||
saveAsButton.MoveAndResize(buttonsX + (topButtonWidth + topButtonGap) * 2, 8, topButtonWidth, topButtonHeight);
|
||||
openButton.Render();
|
||||
saveButton.Render();
|
||||
saveAsButton.Render();
|
||||
|
||||
int canvasX = sidePanelWidth + 12;
|
||||
int canvasY = topBarHeight + 8;
|
||||
int canvasWidth = window.Width - sidePanelWidth * 2 - 24;
|
||||
int canvasHeight = window.Height - canvasY - 12;
|
||||
canvas.MoveAndResize(canvasX, canvasY, canvasWidth, canvasHeight);
|
||||
|
||||
if (canvasWidth > 0 && canvasHeight > 0)
|
||||
{
|
||||
canvas.DrawRectangle(0, 0, canvas.Width, canvas.Height, Color.Black);
|
||||
wm.Update(canvas);
|
||||
}
|
||||
}
|
||||
|
||||
private void UpdateWindowTitle()
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(currentFilePath))
|
||||
{
|
||||
window.Title = "Paint";
|
||||
return;
|
||||
}
|
||||
|
||||
window.Title = $"Paint - {Path.GetFileName(currentFilePath)}";
|
||||
}
|
||||
|
||||
private byte[] BuildBmpBytes()
|
||||
{
|
||||
int width = canvas.Width;
|
||||
int height = canvas.Height;
|
||||
int bytesPerPixel = 4;
|
||||
int pixelDataSize = width * height * bytesPerPixel;
|
||||
int fileSize = 54 + pixelDataSize;
|
||||
byte[] bytes = new byte[fileSize];
|
||||
|
||||
bytes[0] = (byte)'B';
|
||||
bytes[1] = (byte)'M';
|
||||
BitConverter.GetBytes(fileSize).CopyTo(bytes, 2);
|
||||
BitConverter.GetBytes(54).CopyTo(bytes, 10);
|
||||
BitConverter.GetBytes(40).CopyTo(bytes, 14);
|
||||
BitConverter.GetBytes(width).CopyTo(bytes, 18);
|
||||
BitConverter.GetBytes(height).CopyTo(bytes, 22);
|
||||
BitConverter.GetBytes((short)1).CopyTo(bytes, 26);
|
||||
BitConverter.GetBytes((short)32).CopyTo(bytes, 28);
|
||||
BitConverter.GetBytes(pixelDataSize).CopyTo(bytes, 34);
|
||||
|
||||
int offset = 54;
|
||||
for (int y = height - 1; y >= 0; y--)
|
||||
{
|
||||
for (int x = 0; x < width; x++)
|
||||
{
|
||||
Color color = canvas.GetPixel(x, y);
|
||||
bytes[offset++] = color.B;
|
||||
bytes[offset++] = color.G;
|
||||
bytes[offset++] = color.R;
|
||||
bytes[offset++] = color.A;
|
||||
}
|
||||
}
|
||||
|
||||
return bytes;
|
||||
}
|
||||
|
||||
private void SaveCanvas(string path)
|
||||
{
|
||||
try
|
||||
{
|
||||
string sanitizedPath = PathUtil.Sanitize(path.Trim());
|
||||
if (!sanitizedPath.EndsWith(".bmp", StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
sanitizedPath += ".bmp";
|
||||
}
|
||||
|
||||
string directory = Path.GetDirectoryName(sanitizedPath);
|
||||
if (!string.IsNullOrWhiteSpace(directory))
|
||||
{
|
||||
Directory.CreateDirectory(directory);
|
||||
}
|
||||
|
||||
File.WriteAllBytes(sanitizedPath, BuildBmpBytes());
|
||||
currentFilePath = sanitizedPath;
|
||||
UpdateWindowTitle();
|
||||
ShowMessage("Paint", "Saved BMP successfully.");
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
ShowMessage("Paint", $"Save failed: {ex.Message}");
|
||||
}
|
||||
}
|
||||
|
||||
private void OpenImage(string path)
|
||||
{
|
||||
try
|
||||
{
|
||||
string sanitizedPath = PathUtil.Sanitize(path.Trim());
|
||||
if (!File.Exists(sanitizedPath))
|
||||
{
|
||||
ShowMessage("Paint", "File not found.");
|
||||
return;
|
||||
}
|
||||
|
||||
if (!sanitizedPath.EndsWith(".bmp", StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
ShowMessage("Paint", "Only BMP files are supported.");
|
||||
return;
|
||||
}
|
||||
|
||||
Bitmap bitmap = new Bitmap(File.ReadAllBytes(sanitizedPath));
|
||||
canvas.Clear(Color.White);
|
||||
|
||||
int drawWidth = Math.Min(canvas.Width, (int)bitmap.Width);
|
||||
int drawHeight = Math.Min(canvas.Height, (int)bitmap.Height);
|
||||
for (int y = 0; y < drawHeight; y++)
|
||||
{
|
||||
int rowOffset = y * (int)bitmap.Width;
|
||||
for (int x = 0; x < drawWidth; x++)
|
||||
{
|
||||
canvas.DrawPoint(x, y, Color.FromArgb(bitmap.RawData[rowOffset + x]));
|
||||
}
|
||||
}
|
||||
|
||||
canvas.DrawRectangle(0, 0, canvas.Width, canvas.Height, Color.Black);
|
||||
wm.Update(canvas);
|
||||
|
||||
currentFilePath = sanitizedPath;
|
||||
UpdateWindowTitle();
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
ShowMessage("Paint", $"Open failed: {ex.Message}");
|
||||
}
|
||||
}
|
||||
|
||||
private void OpenClicked(int x, int y)
|
||||
{
|
||||
fileBrowser = new FileBrowser(this, wm, (string selectedPath) =>
|
||||
{
|
||||
if (!string.IsNullOrWhiteSpace(selectedPath))
|
||||
{
|
||||
OpenImage(selectedPath);
|
||||
}
|
||||
}, selectDirectoryOnly: false);
|
||||
fileBrowser.Show();
|
||||
}
|
||||
|
||||
private void SaveAsClicked(int x, int y)
|
||||
{
|
||||
fileBrowser = new FileBrowser(this, wm, (string selectedPath) =>
|
||||
{
|
||||
if (!string.IsNullOrWhiteSpace(selectedPath))
|
||||
{
|
||||
SaveCanvas(selectedPath);
|
||||
}
|
||||
}, selectDirectoryOnly: true);
|
||||
fileBrowser.Show();
|
||||
}
|
||||
|
||||
private void SaveClicked(int x, int y)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(currentFilePath))
|
||||
{
|
||||
SaveAsClicked(x, y);
|
||||
return;
|
||||
}
|
||||
|
||||
SaveCanvas(currentFilePath);
|
||||
}
|
||||
|
||||
public override void Start()
|
||||
{
|
||||
base.Start();
|
||||
@@ -61,22 +259,39 @@ namespace CMLeonOS.Gui.Apps.Paint
|
||||
window.Title = "Paint";
|
||||
window.Icon = AppManager.GetAppMetadata("Paint").Icon;
|
||||
window.Closing = TryStop;
|
||||
window.UserResized = Relayout;
|
||||
window.Clear(Color.FromArgb(73, 73, 73));
|
||||
wm.AddWindow(window);
|
||||
|
||||
int canvasWidth = 384;
|
||||
int canvasHeight = 256;
|
||||
canvas = new Window(this, (window.Width / 2) - (canvasWidth / 2), (window.Height / 2) - (canvasHeight / 2), canvasWidth, canvasHeight);
|
||||
canvas = new Window(this, 0, 0, 1, 1);
|
||||
canvas.RelativeTo = window;
|
||||
canvas.OnDown = CanvasDown;
|
||||
canvas.Clear(Color.White);
|
||||
wm.AddWindow(canvas);
|
||||
|
||||
toolBox = new ToolBox(this, 0, 0, 128, window.Height);
|
||||
openButton = new Button(window, 0, 0, 1, 1);
|
||||
openButton.Text = "Open";
|
||||
openButton.OnClick = OpenClicked;
|
||||
wm.AddWindow(openButton);
|
||||
|
||||
saveButton = new Button(window, 0, 0, 1, 1);
|
||||
saveButton.Text = "Save";
|
||||
saveButton.OnClick = SaveClicked;
|
||||
wm.AddWindow(saveButton);
|
||||
|
||||
saveAsButton = new Button(window, 0, 0, 1, 1);
|
||||
saveAsButton.Text = "Save As";
|
||||
saveAsButton.OnClick = SaveAsClicked;
|
||||
wm.AddWindow(saveAsButton);
|
||||
|
||||
toolBox = new ToolBox(this, 0, 0, sidePanelWidth, window.Height);
|
||||
toolBox.RelativeTo = window;
|
||||
colourPicker = new ColourPicker(this, window.Width - 128, 0, 128, window.Height);
|
||||
colourPicker = new ColourPicker(this, window.Width - sidePanelWidth, 0, sidePanelWidth, window.Height);
|
||||
colourPicker.RelativeTo = window;
|
||||
|
||||
UpdateWindowTitle();
|
||||
Relayout();
|
||||
|
||||
wm.Update(window);
|
||||
}
|
||||
|
||||
|
||||
@@ -195,14 +195,14 @@ namespace CMLeonOS.Gui.Apps
|
||||
|
||||
appearance.DrawString("Wallpaper", Color.Gray, 12, 132);
|
||||
appearance.DrawString(GetWallpaperLabel(), Color.Black, 12, 152);
|
||||
appearance.DrawString("Choose a BMP file or restore the embedded default wallpaper.", Color.Gray, 12, 172);
|
||||
appearance.DrawString("Use a BMP file or restore the default wallpaper.", Color.Gray, 12, 170);
|
||||
|
||||
Button chooseWallpaper = new Button(appearance, 12, 198, 132, 24);
|
||||
Button chooseWallpaper = new Button(appearance, 12, 192, 132, 24);
|
||||
chooseWallpaper.Text = "Choose BMP";
|
||||
chooseWallpaper.OnClick = (_, _) => OpenWallpaperBrowser();
|
||||
wm.AddWindow(chooseWallpaper);
|
||||
|
||||
Button defaultWallpaper = new Button(appearance, 154, 198, 132, 24);
|
||||
Button defaultWallpaper = new Button(appearance, 154, 192, 132, 24);
|
||||
defaultWallpaper.Text = "Use Default";
|
||||
defaultWallpaper.OnClick = (_, _) => ApplyWallpaper(string.Empty);
|
||||
wm.AddWindow(defaultWallpaper);
|
||||
|
||||
Reference in New Issue
Block a user