Skip to content

Commit 9017f19

Browse files
committed
Refactor hole punch logic to reduce duplication
1 parent 94604ea commit 9017f19

1 file changed

Lines changed: 88 additions & 103 deletions

File tree

WindowsEdgeLight/MainWindow.xaml.cs

Lines changed: 88 additions & 103 deletions
Original file line numberDiff line numberDiff line change
@@ -354,126 +354,111 @@ private void HandleMouseMove(int screenX, int screenY)
354354
// --- Main Window Logic ---
355355
if (frameOuterRect != null && frameInnerRect != null && hoverCursorRing != null && baseFrameGeometry != null)
356356
{
357-
// Manual coordinate calculation for Main Window as well to be safe with mixed DPIs
358-
// We positioned the window using _dpiScaleX/Y relative to the screen WorkingArea.
359357
var screen = availableMonitors.Length > 0 ? availableMonitors[currentMonitorIndex] : Screen.PrimaryScreen;
360358
if (screen != null)
361359
{
362-
double relX = (screenX - screen.WorkingArea.X) / _dpiScaleX;
363-
double relY = (screenY - screen.WorkingArea.Y) / _dpiScaleY;
364-
var windowPt = new System.Windows.Point(relX, relY);
360+
ApplyHolePunchEffect(
361+
screenX, screenY,
362+
screen,
363+
_dpiScaleX, _dpiScaleY,
364+
frameOuterRect.Value, frameInnerRect.Value,
365+
hoverCursorRing,
366+
EdgeLightBorder,
367+
baseFrameGeometry,
368+
pathOffsetX, pathOffsetY,
369+
(ring, x, y) => { Canvas.SetLeft(ring, x); Canvas.SetTop(ring, y); }
370+
);
371+
}
372+
}
365373

366-
// Existing frame band detection (outer minus inner)
367-
bool inFrameBand = frameOuterRect.Value.Contains(windowPt) && !frameInnerRect.Value.Contains(windowPt);
374+
// --- Additional Windows Logic ---
375+
foreach (var ctx in additionalMonitorWindows)
376+
{
377+
try
378+
{
379+
ApplyHolePunchEffect(
380+
screenX, screenY,
381+
ctx.Screen,
382+
ctx.DpiScaleX, ctx.DpiScaleY,
383+
ctx.FrameOuterRect, ctx.FrameInnerRect,
384+
ctx.HoverRing,
385+
ctx.BorderPath,
386+
ctx.BaseGeometry,
387+
ctx.PathOffsetX, ctx.PathOffsetY,
388+
(ring, x, y) => { ring.Margin = new Thickness(x, y, 0, 0); }
389+
);
390+
}
391+
catch (InvalidOperationException)
392+
{
393+
// Can happen if window is closing or not ready
394+
}
395+
}
396+
}
368397

369-
// Early detection zone just inside the inner edge: a band with thickness = hole radius (cursor ring radius)
370-
double ringDiameter = hoverCursorRing.Width;
371-
double holeRadius = ringDiameter / 2; // match ring size
372-
var innerProximityRect = new Rect(
373-
frameInnerRect.Value.X + holeRadius,
374-
frameInnerRect.Value.Y + holeRadius,
375-
frameInnerRect.Value.Width - (holeRadius * 2),
376-
frameInnerRect.Value.Height - (holeRadius * 2));
398+
private void ApplyHolePunchEffect(
399+
int screenX, int screenY,
400+
Screen screen,
401+
double dpiScaleX, double dpiScaleY,
402+
Rect frameOuterRect, Rect frameInnerRect,
403+
Ellipse hoverRing,
404+
System.Windows.Shapes.Path borderPath,
405+
Geometry baseGeometry,
406+
double pathOffsetX, double pathOffsetY,
407+
Action<Ellipse, double, double> positionRing)
408+
{
409+
// Manual coordinate calculation to avoid PointFromScreen issues across monitors/DPIs
410+
// We positioned the window using dpiScaleX/Y relative to the screen WorkingArea.
411+
double relX = (screenX - screen.WorkingArea.X) / dpiScaleX;
412+
double relY = (screenY - screen.WorkingArea.Y) / dpiScaleY;
413+
var windowPt = new System.Windows.Point(relX, relY);
377414

378-
// Near from inside means inside innerRect but within holeRadius of its edge (i.e., not deep inside innerProximityRect)
379-
bool nearFromInside = frameInnerRect.Value.Contains(windowPt) && !innerProximityRect.Contains(windowPt);
415+
// Existing frame band detection (outer minus inner)
416+
bool inFrameBand = frameOuterRect.Contains(windowPt) && !frameInnerRect.Contains(windowPt);
380417

381-
bool overFrame = inFrameBand || nearFromInside;
418+
// Early detection zone just inside the inner edge: a band with thickness = hole radius (cursor ring radius)
419+
double ringDiameter = hoverRing.Width;
420+
double holeRadius = ringDiameter / 2; // match ring size
421+
var innerProximityRect = new Rect(
422+
frameInnerRect.X + holeRadius,
423+
frameInnerRect.Y + holeRadius,
424+
frameInnerRect.Width - (holeRadius * 2),
425+
frameInnerRect.Height - (holeRadius * 2));
382426

383-
if (overFrame)
384-
{
385-
Canvas.SetLeft(hoverCursorRing, windowPt.X - ringDiameter / 2);
386-
Canvas.SetTop(hoverCursorRing, windowPt.Y - ringDiameter / 2);
387-
if (hoverCursorRing.Visibility != Visibility.Visible)
388-
{
389-
hoverCursorRing.Visibility = Visibility.Visible;
390-
}
427+
// Near from inside means inside innerRect but within holeRadius of its edge (i.e., not deep inside innerProximityRect)
428+
bool nearFromInside = frameInnerRect.Contains(windowPt) && !innerProximityRect.Contains(windowPt);
391429

392-
// Punch a transparent hole under the ring by excluding a circle geometry from the frame
393-
// Convert window coordinates to geometry local coordinates by subtracting stored offsets
394-
var localCenter = new System.Windows.Point(windowPt.X - pathOffsetX, windowPt.Y - pathOffsetY);
395-
var hole = new EllipseGeometry(localCenter, holeRadius, holeRadius);
396-
EdgeLightBorder.Data = new CombinedGeometry(GeometryCombineMode.Exclude, baseFrameGeometry, hole);
397-
}
398-
else
399-
{
400-
if (hoverCursorRing.Visibility != Visibility.Collapsed)
401-
{
402-
hoverCursorRing.Visibility = Visibility.Collapsed;
403-
}
430+
bool overFrame = inFrameBand || nearFromInside;
404431

405-
if (EdgeLightBorder.Visibility != Visibility.Visible)
406-
{
407-
EdgeLightBorder.Visibility = Visibility.Visible;
408-
}
409-
// Restore original geometry (remove hole)
410-
if (baseFrameGeometry != null && EdgeLightBorder.Data != baseFrameGeometry)
411-
{
412-
EdgeLightBorder.Data = baseFrameGeometry;
413-
}
414-
}
432+
if (overFrame)
433+
{
434+
positionRing(hoverRing, windowPt.X - ringDiameter / 2, windowPt.Y - ringDiameter / 2);
435+
436+
if (hoverRing.Visibility != Visibility.Visible)
437+
{
438+
hoverRing.Visibility = Visibility.Visible;
415439
}
416-
}
417440

418-
// --- Additional Windows Logic ---
419-
int monitorIdx = 0;
420-
foreach (var ctx in additionalMonitorWindows)
441+
// Punch a transparent hole under the ring by excluding a circle geometry from the frame
442+
// Convert window coordinates to geometry local coordinates by subtracting stored offsets
443+
var localCenter = new System.Windows.Point(windowPt.X - pathOffsetX, windowPt.Y - pathOffsetY);
444+
var hole = new EllipseGeometry(localCenter, holeRadius, holeRadius);
445+
borderPath.Data = new CombinedGeometry(GeometryCombineMode.Exclude, baseGeometry, hole);
446+
}
447+
else
421448
{
422-
monitorIdx++;
423-
try
449+
if (hoverRing.Visibility != Visibility.Collapsed)
424450
{
425-
// Manual coordinate calculation to avoid PointFromScreen issues across monitors/DPIs
426-
// We positioned the window using ctx.DpiScaleX/Y relative to the screen WorkingArea.
427-
// So we reverse that logic here.
428-
double relX = (screenX - ctx.Screen.WorkingArea.X) / ctx.DpiScaleX;
429-
double relY = (screenY - ctx.Screen.WorkingArea.Y) / ctx.DpiScaleY;
430-
var windowPt = new System.Windows.Point(relX, relY);
431-
432-
bool inFrameBand = ctx.FrameOuterRect.Contains(windowPt) && !ctx.FrameInnerRect.Contains(windowPt);
433-
434-
double ringDiameter = ctx.HoverRing.Width;
435-
double holeRadius = ringDiameter / 2;
436-
var innerProximityRect = new Rect(
437-
ctx.FrameInnerRect.X + holeRadius,
438-
ctx.FrameInnerRect.Y + holeRadius,
439-
ctx.FrameInnerRect.Width - (holeRadius * 2),
440-
ctx.FrameInnerRect.Height - (holeRadius * 2));
441-
442-
bool nearFromInside = ctx.FrameInnerRect.Contains(windowPt) && !innerProximityRect.Contains(windowPt);
443-
bool overFrame = inFrameBand || nearFromInside;
451+
hoverRing.Visibility = Visibility.Collapsed;
452+
}
444453

445-
if (overFrame)
446-
{
447-
// For Grid/Canvas positioning, we need to check how the ring is added.
448-
// In CreateMonitorWindow, we added it to a Grid. Grid doesn't support Canvas.SetLeft/Top directly unless it's in a Canvas.
449-
// Wait, CreateMonitorWindow adds it to a Grid.
450-
// I should have used a Canvas or set Margins.
451-
// Let's assume I can set Margins for now since it's in a Grid.
452-
453-
ctx.HoverRing.Margin = new Thickness(windowPt.X - ringDiameter / 2, windowPt.Y - ringDiameter / 2, 0, 0);
454-
455-
if (ctx.HoverRing.Visibility != Visibility.Visible)
456-
ctx.HoverRing.Visibility = Visibility.Visible;
457-
458-
var localCenter = new System.Windows.Point(windowPt.X - ctx.PathOffsetX, windowPt.Y - ctx.PathOffsetY);
459-
var hole = new EllipseGeometry(localCenter, holeRadius, holeRadius);
460-
ctx.BorderPath.Data = new CombinedGeometry(GeometryCombineMode.Exclude, ctx.BaseGeometry, hole);
461-
}
462-
else
463-
{
464-
if (ctx.HoverRing.Visibility != Visibility.Collapsed)
465-
ctx.HoverRing.Visibility = Visibility.Collapsed;
466-
467-
if (ctx.BorderPath.Visibility != Visibility.Visible)
468-
ctx.BorderPath.Visibility = Visibility.Visible;
469-
470-
if (ctx.BorderPath.Data != ctx.BaseGeometry)
471-
ctx.BorderPath.Data = ctx.BaseGeometry;
472-
}
454+
if (borderPath.Visibility != Visibility.Visible)
455+
{
456+
borderPath.Visibility = Visibility.Visible;
473457
}
474-
catch (InvalidOperationException)
458+
// Restore original geometry (remove hole)
459+
if (baseGeometry != null && borderPath.Data != baseGeometry)
475460
{
476-
// Can happen if window is closing or not ready
461+
borderPath.Data = baseGeometry;
477462
}
478463
}
479464
}

0 commit comments

Comments
 (0)