control work fixes

This commit is contained in:
2026-01-17 08:51:13 +00:00
parent dc52f7f2bc
commit 9451611c3a
10 changed files with 169 additions and 37 deletions

View File

@@ -209,6 +209,17 @@ public class SkiaEntry : SkiaView, IInputContext
typeof(SkiaEntry),
0);
/// <summary>
/// Bindable property for SelectAllOnDoubleClick.
/// When true, double-clicking selects all text instead of just the word.
/// </summary>
public static readonly BindableProperty SelectAllOnDoubleClickProperty =
BindableProperty.Create(
nameof(SelectAllOnDoubleClick),
typeof(bool),
typeof(SkiaEntry),
false);
/// <summary>
/// Bindable property for IsReadOnly.
/// </summary>
@@ -504,6 +515,16 @@ public class SkiaEntry : SkiaView, IInputContext
set => SetValue(MaxLengthProperty, value);
}
/// <summary>
/// Gets or sets whether double-clicking selects all text instead of just the word.
/// Useful for URL bars and similar inputs.
/// </summary>
public bool SelectAllOnDoubleClick
{
get => (bool)GetValue(SelectAllOnDoubleClickProperty);
set => SetValue(SelectAllOnDoubleClickProperty, value);
}
/// <summary>
/// Gets or sets whether the entry is read-only.
/// </summary>
@@ -1372,13 +1393,11 @@ public class SkiaEntry : SkiaView, IInputContext
public override void OnPointerPressed(PointerEventArgs e)
{
Console.WriteLine($"[SkiaEntry] OnPointerPressed Button={e.Button} at ({e.X}, {e.Y})");
if (!IsEnabled) return;
// Handle right-click context menu
if (e.Button == PointerButton.Right)
{
Console.WriteLine("[SkiaEntry] Right-click detected, showing context menu");
ShowContextMenu(e.X, e.Y);
return;
}
@@ -1409,15 +1428,22 @@ public class SkiaEntry : SkiaView, IInputContext
var clickX = e.X - (float)screenBounds.Left - (float)Padding.Left + _scrollOffset;
_cursorPosition = GetCharacterIndexAtX(clickX);
// Check for double-click (select word)
// Check for double-click (select word or select all)
var now = DateTime.UtcNow;
var timeSinceLastClick = (now - _lastClickTime).TotalMilliseconds;
var distanceFromLastClick = Math.Abs(e.X - _lastClickX);
if (timeSinceLastClick < DoubleClickThresholdMs && distanceFromLastClick < 10)
{
// Double-click: select the word at cursor
SelectWordAtCursor();
// Double-click: select all or select word based on property
if (SelectAllOnDoubleClick)
{
SelectAll();
}
else
{
SelectWordAtCursor();
}
_lastClickTime = DateTime.MinValue; // Reset to prevent triple-click issues
_isSelecting = false;
}

View File

@@ -805,12 +805,9 @@ public class SkiaImageButton : SkiaView
}
// Fill (3) and Start (0) both use y = bounds.Top
var result1 = new Rect(x, y, finalWidth, finalHeight);
Console.WriteLine($"[SkiaImageButton] ArrangeOverride output (aligned): Y={result1.Y}, Height={result1.Height}");
return result1;
return new Rect(x, y, finalWidth, finalHeight);
}
Console.WriteLine($"[SkiaImageButton] ArrangeOverride output (unchanged): Y={bounds.Y}, Height={bounds.Height}");
return bounds;
}

View File

@@ -248,13 +248,7 @@ public abstract class SkiaLayoutView : SkiaView
public override SkiaView? HitTest(float x, float y)
{
if (!IsVisible || !IsEnabled || !Bounds.Contains(x, y))
{
if (this is SkiaBorder)
{
Console.WriteLine($"[SkiaBorder.HitTest] Miss - x={x}, y={y}, Bounds={Bounds}, IsVisible={IsVisible}, IsEnabled={IsEnabled}");
}
return null;
}
// Hit test children in reverse order (top-most first)
for (int i = _children.Count - 1; i >= 0; i--)
@@ -262,19 +256,9 @@ public abstract class SkiaLayoutView : SkiaView
var child = _children[i];
var hit = child.HitTest(x, y);
if (hit != null)
{
if (this is SkiaBorder)
{
Console.WriteLine($"[SkiaBorder.HitTest] Hit child - x={x}, y={y}, Bounds={Bounds}, child={hit.GetType().Name}");
}
return hit;
}
}
if (this is SkiaBorder)
{
Console.WriteLine($"[SkiaBorder.HitTest] Hit self - x={x}, y={y}, Bounds={Bounds}, children={_children.Count}");
}
return this;
}

View File

@@ -187,9 +187,22 @@ public class SkiaProgressBar : SkiaView
var barHeight = (float)BarHeight;
var cornerRadius = (float)CornerRadius;
float midY = bounds.MidY;
float trackTop = midY - barHeight / 2f;
float trackBottom = midY + barHeight / 2f;
// If bounds height is small (HeightRequest was set), use the full bounds height
// Otherwise, center the bar vertically within the bounds
float trackTop, trackBottom;
if (bounds.Height <= barHeight + 4)
{
// Small bounds - fill the height
trackTop = bounds.Top;
trackBottom = bounds.Bottom;
}
else
{
// Large bounds - center the bar
float midY = bounds.MidY;
trackTop = midY - barHeight / 2f;
trackBottom = midY + barHeight / 2f;
}
// Get colors
var trackColorSK = ToSKColor(TrackColor);
@@ -246,8 +259,11 @@ public class SkiaProgressBar : SkiaView
protected override Size MeasureOverride(Size availableSize)
{
var barHeight = BarHeight;
return new Size(200, barHeight + 8);
// Respect HeightRequest if set, otherwise use BarHeight with padding
var height = HeightRequest >= 0 ? HeightRequest : BarHeight + 8;
// Respect WidthRequest if set, otherwise use available width or default
var width = WidthRequest >= 0 ? WidthRequest : (availableSize.Width > 0 ? availableSize.Width : 200);
return new Size(width, height);
}
#endregion

View File

@@ -6,6 +6,7 @@ using Microsoft.Maui.Controls.Shapes;
using Microsoft.Maui.Graphics;
using Microsoft.Maui.Platform.Linux;
using Microsoft.Maui.Platform.Linux.Handlers;
using Microsoft.Maui.Platform.Linux.Native;
using Microsoft.Maui.Platform.Linux.Rendering;
using Microsoft.Maui.Platform.Linux.Services;
using Microsoft.Maui.Platform.Linux.Window;
@@ -1270,8 +1271,27 @@ public abstract class SkiaView : BindableObject, IDisposable, IAccessible
/// <summary>
/// Requests that this view be redrawn.
/// Thread-safe - will marshal to GTK thread if needed.
/// </summary>
public void Invalidate()
{
// Check if we're on the GTK thread - if not, marshal the entire call
int currentThread = Environment.CurrentManagedThreadId;
int gtkThread = LinuxApplication.GtkThreadId;
if (gtkThread != 0 && currentThread != gtkThread)
{
GLibNative.IdleAdd(() =>
{
InvalidateInternal();
return false;
});
return;
}
InvalidateInternal();
}
private void InvalidateInternal()
{
LinuxApplication.LogInvalidate(GetType().Name);
Invalidated?.Invoke(this, EventArgs.Empty);
@@ -1286,7 +1306,7 @@ public abstract class SkiaView : BindableObject, IDisposable, IAccessible
if (_parent != null)
{
_parent.Invalidate();
_parent.InvalidateInternal();
}
else
{