New GUI overhaul!, version 3.0.1.0
This commit is contained in:
parent
c05d6c9d1b
commit
79304baaad
16 changed files with 1579 additions and 4589 deletions
395
MosswartMassacre/Views/VVSBaseView.cs
Normal file
395
MosswartMassacre/Views/VVSBaseView.cs
Normal file
|
|
@ -0,0 +1,395 @@
|
|||
using System;
|
||||
using System.Drawing;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Timers;
|
||||
using VirindiViewService;
|
||||
using VirindiViewService.XMLParsers;
|
||||
|
||||
namespace MosswartMassacre.Views
|
||||
{
|
||||
/// <summary>
|
||||
/// Base class for VVS (VirindiViewService) based views.
|
||||
/// Replaces the wrapper-based BaseView with direct VVS integration.
|
||||
/// </summary>
|
||||
public class VVSBaseView : IDisposable
|
||||
{
|
||||
#region Windows API for boundary checking
|
||||
[StructLayout(LayoutKind.Sequential)]
|
||||
public struct RECT
|
||||
{
|
||||
public int Left;
|
||||
public int Top;
|
||||
public int Right;
|
||||
public int Bottom;
|
||||
|
||||
public int Width { get { return Right - Left; } }
|
||||
public int Height { get { return Bottom - Top; } }
|
||||
}
|
||||
|
||||
[DllImport("user32.dll", SetLastError = true)]
|
||||
[return: MarshalAs(UnmanagedType.Bool)]
|
||||
public static extern bool GetWindowRect(IntPtr hWnd, ref RECT lpRect);
|
||||
#endregion
|
||||
|
||||
#region Core VVS Components
|
||||
protected HudView view;
|
||||
protected ViewProperties properties;
|
||||
protected ControlGroup controls;
|
||||
protected PluginCore pluginCore;
|
||||
#endregion
|
||||
|
||||
#region Position Management
|
||||
private Timer positionSaveTimer;
|
||||
#endregion
|
||||
|
||||
public VVSBaseView(PluginCore core)
|
||||
{
|
||||
pluginCore = core;
|
||||
InitializePositionTimer();
|
||||
}
|
||||
|
||||
#region VVS Initialization
|
||||
protected void CreateFromXMLResource(string resourcePath, bool doIcon = true, bool doTitle = true)
|
||||
{
|
||||
try
|
||||
{
|
||||
// Parse XML using VVS Decal3XMLParser
|
||||
new Decal3XMLParser().ParseFromResource(resourcePath, out properties, out controls);
|
||||
|
||||
// Set window properties
|
||||
if (doTitle)
|
||||
{
|
||||
properties.Title = "Mosswart Massacre v3.0";
|
||||
}
|
||||
|
||||
if (doIcon)
|
||||
{
|
||||
// Use default icon for now - can be customized later
|
||||
properties.Icon = 7735; // Same icon as in XML
|
||||
}
|
||||
|
||||
// Create the HudView
|
||||
view = new HudView(properties, controls);
|
||||
|
||||
// Subscribe to essential events
|
||||
view.VisibleChanged += View_VisibleChanged;
|
||||
view.Moved += View_Moved;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
PluginCore.WriteToChat($"Error creating VVS view from {resourcePath}: {ex.Message}");
|
||||
PluginCore.WriteToChat($"Stack trace: {ex.StackTrace}");
|
||||
}
|
||||
}
|
||||
|
||||
protected void CreateFromXMLString(string xmlString, bool doIcon = true, bool doTitle = true)
|
||||
{
|
||||
try
|
||||
{
|
||||
// Parse XML string using VVS Decal3XMLParser
|
||||
new Decal3XMLParser().Parse(xmlString, out properties, out controls);
|
||||
|
||||
if (doTitle)
|
||||
{
|
||||
properties.Title = "Mosswart Massacre v3.0";
|
||||
}
|
||||
|
||||
if (doIcon)
|
||||
{
|
||||
properties.Icon = 7735;
|
||||
}
|
||||
|
||||
view = new HudView(properties, controls);
|
||||
view.VisibleChanged += View_VisibleChanged;
|
||||
view.Moved += View_Moved;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
PluginCore.WriteToChat($"Error creating VVS view from XML string: {ex.Message}");
|
||||
}
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region Control Access
|
||||
/// <summary>
|
||||
/// Get a control by name with proper type casting.
|
||||
/// Usage: var button = GetControl<HudButton>("btnExample");
|
||||
/// </summary>
|
||||
protected T GetControl<T>(string controlName) where T : class
|
||||
{
|
||||
try
|
||||
{
|
||||
if (view != null && view[controlName] != null)
|
||||
{
|
||||
return view[controlName] as T;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
PluginCore.WriteToChat($"Error getting control '{controlName}': {ex.Message}");
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get a control by name (alternative syntax)
|
||||
/// Usage: var button = (HudButton)GetControl("btnExample");
|
||||
/// </summary>
|
||||
protected object GetControl(string controlName)
|
||||
{
|
||||
try
|
||||
{
|
||||
return view?[controlName];
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
PluginCore.WriteToChat($"Error getting control '{controlName}': {ex.Message}");
|
||||
return null;
|
||||
}
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region Window Management
|
||||
protected virtual void SaveWindowPosition()
|
||||
{
|
||||
try
|
||||
{
|
||||
if (view != null && PluginSettings.Instance != null)
|
||||
{
|
||||
PluginSettings.Instance.MainWindowX = view.Location.X;
|
||||
PluginSettings.Instance.MainWindowY = view.Location.Y;
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
PluginCore.WriteToChat($"Error saving window position: {ex.Message}");
|
||||
}
|
||||
}
|
||||
|
||||
protected virtual void RestoreWindowPosition()
|
||||
{
|
||||
try
|
||||
{
|
||||
if (view != null && PluginSettings.Instance != null)
|
||||
{
|
||||
view.Location = new Point(
|
||||
PluginSettings.Instance.MainWindowX,
|
||||
PluginSettings.Instance.MainWindowY
|
||||
);
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
PluginCore.WriteToChat($"Error restoring window position: {ex.Message}");
|
||||
}
|
||||
}
|
||||
|
||||
protected void KeepWindowInBounds()
|
||||
{
|
||||
try
|
||||
{
|
||||
if (view == null) return;
|
||||
|
||||
RECT rect = new RECT();
|
||||
IntPtr gameWindowHandle = PluginCore.MyHost?.Decal?.Hwnd ?? IntPtr.Zero;
|
||||
|
||||
if (gameWindowHandle != IntPtr.Zero && GetWindowRect(gameWindowHandle, ref rect))
|
||||
{
|
||||
Point currentLocation = view.Location;
|
||||
int viewWidth = view.Width;
|
||||
int viewHeight = view.Height;
|
||||
|
||||
bool needsUpdate = false;
|
||||
|
||||
// Check right boundary
|
||||
if (currentLocation.X + viewWidth > rect.Width)
|
||||
{
|
||||
currentLocation.X = rect.Width - viewWidth;
|
||||
needsUpdate = true;
|
||||
}
|
||||
// Check left boundary
|
||||
else if (currentLocation.X < 0)
|
||||
{
|
||||
currentLocation.X = 20;
|
||||
needsUpdate = true;
|
||||
}
|
||||
|
||||
// Check bottom boundary
|
||||
if (currentLocation.Y + viewHeight > rect.Height)
|
||||
{
|
||||
currentLocation.Y = rect.Height - viewHeight;
|
||||
needsUpdate = true;
|
||||
}
|
||||
// Check top boundary
|
||||
else if (currentLocation.Y < 0)
|
||||
{
|
||||
currentLocation.Y = 20;
|
||||
needsUpdate = true;
|
||||
}
|
||||
|
||||
if (needsUpdate)
|
||||
{
|
||||
view.Location = currentLocation;
|
||||
}
|
||||
}
|
||||
}
|
||||
catch
|
||||
{
|
||||
// Silently ignore boundary check errors
|
||||
}
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region Position Timer Management
|
||||
private void InitializePositionTimer()
|
||||
{
|
||||
positionSaveTimer = new Timer(2000); // 2 second delay after movement stops
|
||||
positionSaveTimer.Elapsed += (s, e) => {
|
||||
SaveWindowPosition();
|
||||
positionSaveTimer.Stop();
|
||||
};
|
||||
}
|
||||
|
||||
private void View_Moved(object sender, EventArgs e)
|
||||
{
|
||||
try
|
||||
{
|
||||
// Reset timer when window moves
|
||||
if (positionSaveTimer != null)
|
||||
{
|
||||
if (positionSaveTimer.Enabled)
|
||||
positionSaveTimer.Stop();
|
||||
|
||||
positionSaveTimer.Start();
|
||||
}
|
||||
}
|
||||
catch
|
||||
{
|
||||
// Ignore timer errors
|
||||
}
|
||||
}
|
||||
|
||||
private void View_VisibleChanged(object sender, EventArgs e)
|
||||
{
|
||||
try
|
||||
{
|
||||
if (view.Visible)
|
||||
{
|
||||
KeepWindowInBounds();
|
||||
}
|
||||
}
|
||||
catch
|
||||
{
|
||||
// Ignore visibility change errors
|
||||
}
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region Public Interface
|
||||
public virtual void Initialize()
|
||||
{
|
||||
try
|
||||
{
|
||||
RestoreWindowPosition();
|
||||
KeepWindowInBounds();
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
PluginCore.WriteToChat($"Error initializing VVS view: {ex.Message}");
|
||||
}
|
||||
}
|
||||
|
||||
public virtual void Show()
|
||||
{
|
||||
if (view != null)
|
||||
{
|
||||
view.Visible = true;
|
||||
}
|
||||
}
|
||||
|
||||
public virtual void Hide()
|
||||
{
|
||||
if (view != null)
|
||||
{
|
||||
view.Visible = false;
|
||||
}
|
||||
}
|
||||
|
||||
public virtual void Toggle()
|
||||
{
|
||||
if (view != null)
|
||||
{
|
||||
view.Visible = !view.Visible;
|
||||
}
|
||||
}
|
||||
|
||||
public bool IsVisible
|
||||
{
|
||||
get { return view?.Visible ?? false; }
|
||||
}
|
||||
|
||||
public Point Location
|
||||
{
|
||||
get { return view?.Location ?? Point.Empty; }
|
||||
set { if (view != null) view.Location = value; }
|
||||
}
|
||||
|
||||
public Size Size
|
||||
{
|
||||
get { return view != null ? new Size(view.Width, view.Height) : Size.Empty; }
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region IDisposable Support
|
||||
private bool disposedValue = false;
|
||||
|
||||
protected virtual void Dispose(bool disposing)
|
||||
{
|
||||
if (!disposedValue)
|
||||
{
|
||||
if (disposing)
|
||||
{
|
||||
try
|
||||
{
|
||||
// Save final position before disposal
|
||||
SaveWindowPosition();
|
||||
|
||||
// Clean up timers
|
||||
if (positionSaveTimer != null)
|
||||
{
|
||||
positionSaveTimer.Stop();
|
||||
positionSaveTimer.Dispose();
|
||||
positionSaveTimer = null;
|
||||
}
|
||||
|
||||
// Clean up VVS view
|
||||
if (view != null)
|
||||
{
|
||||
view.VisibleChanged -= View_VisibleChanged;
|
||||
view.Moved -= View_Moved;
|
||||
view.Dispose();
|
||||
view = null;
|
||||
}
|
||||
|
||||
// Clean up VVS objects
|
||||
properties = null;
|
||||
controls = null;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
PluginCore.WriteToChat($"Error disposing VVS view: {ex.Message}");
|
||||
}
|
||||
}
|
||||
disposedValue = true;
|
||||
}
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
Dispose(true);
|
||||
GC.SuppressFinalize(this);
|
||||
}
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue