Skip to content
5 changes: 3 additions & 2 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -27,14 +27,15 @@ Thanks to the following contributors who worked on this release:
- Support for color picking in `SimpleEffectDialog`. Useful for add-in developers (#1611)
- The text tool now supports using Ctrl+Backspace to delete words (#1680)
- Added a Windows ARM64 installer (#1699, #1378)
- The selection of an area on the canvas is now being projected and highlighted on the rulers (#1723)

### Changed
- Packaging changes
- Updated dependencies to require GTK 4.18+ and libadwaita 1.7+
- Pinta now consistently uses an application ID of `com.github.PintaProject.Pinta`, which previously had been applied in patches for downstream packages (#1706, #1419)
- Breaking API changes for add-ins will require add-ins to be rebuilt against Pinta 3.1
- Attributes used for effect configuration properties (`CaptionAttribute`, `MaximumValueAttribute`, ...) are now in the `Pinta.Core` assembly and the `Pinta.Core` namespace
- Methods `RegisterEffect`, `UnregisterInstanceOfEffect`, `RegisterAdjustment`, and `UnregisterInstanceOfAdjustment` in `EffectsManager` are now generic
- Attributes used for effect configuration properties (`CaptionAttribute`, `MaximumValueAttribute`, ...) are now in the `Pinta.Core` assembly and the `Pinta.Core` namespace (#1665)
- Methods `RegisterEffect`, `UnregisterInstanceOfEffect`, `RegisterAdjustment`, and `UnregisterInstanceOfAdjustment` in `EffectsManager` are now generic (#1678)
- Removed use of deprecated Gtk.FontButton (#1421)
- View menu moved from hamburger menu to dedicated button (#1428, #1471)
- Updated the application icon on macOS to better match the platform's icon style guidelines (#1572)
Expand Down
14 changes: 14 additions & 0 deletions Pinta.Gui.Widgets/Widgets/Canvas/CanvasWindow.cs
Original file line number Diff line number Diff line change
Expand Up @@ -146,6 +146,20 @@ public CanvasWindow (
// Also update if the view size changed without affecting the size of
// the canvas widget (e.g. when zoomed out and no scrollbars are required)
document.Workspace.ViewSizeChanged += UpdateRulerRange;
document.SelectionChanged += UpdateRulerSelection;
}

private void UpdateRulerSelection (object? sender, EventArgs e)
{
if (document.Selection.Visible) {
RectangleD bounds = document.Selection.GetBounds ();
horizontal_ruler.SetSelectionRange (bounds.Left, bounds.Left + bounds.Width);
vertical_ruler.SetSelectionRange (bounds.Top, bounds.Top + bounds.Height);
} else {
// If there's no selection, clear the highlight
horizontal_ruler.SetSelectionRange (null, null);
vertical_ruler.SetSelectionRange (null, null);
}
}

private void HandleMotion (
Expand Down
59 changes: 54 additions & 5 deletions Pinta.Gui.Widgets/Widgets/Ruler.cs
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@
using System;
using System.Collections.Immutable;
using System.Diagnostics;
using System.Runtime.CompilerServices;
using Cairo;
using Pinta.Core;

Expand All @@ -51,6 +52,20 @@ public sealed class Ruler : Gtk.DrawingArea
private Surface? cached_surface = null;
private Size? last_known_size = null;

private double? selection_start = null;
private double? selection_end = null;

public void SetSelectionRange (double? start, double? end)
{
if (selection_start == start && selection_end == end)
return;

selection_start = start;
selection_end = end;

QueueDraw ();
}

/// <summary>
/// Whether the ruler is horizontal or vertical.
/// </summary>
Expand Down Expand Up @@ -162,15 +177,15 @@ private readonly record struct RulerDrawSettings (
int Start,
int End,
double MarkerPosition,
RectangleD RulerBottomLine,
RectangleD RulerOuterLine,
Size EffectiveSize,
Color Color,
Gtk.Orientation Orientation);
private RulerDrawSettings CreateSettings (Size preliminarySize)
{
GetStyleContext ().GetColor (out Color color);

RectangleD rulerBottomLine = Orientation switch {
RectangleD rulerOuterLine = Orientation switch {

Gtk.Orientation.Vertical => new (
X: preliminarySize.Width - 1,
Expand Down Expand Up @@ -256,8 +271,8 @@ private RulerDrawSettings CreateSettings (Size preliminarySize)
UnitsPerTick: unitsPerTick,
Start: (int) Math.Floor (scaledLower * ticksPerUnit),
End: (int) Math.Ceiling (scaledUpper * ticksPerUnit),
MarkerPosition: (Position - Lower) * (effectiveSize.Width / (Upper - Lower)),
RulerBottomLine: rulerBottomLine,
MarkerPosition: GetPositionOnRuler (Position, effectiveSize.Width),
RulerOuterLine: rulerOuterLine,
EffectiveSize: effectiveSize,
Color: color,
Orientation: Orientation);
Expand All @@ -274,6 +289,31 @@ private void Draw (Context cr, Size preliminarySize)

cached_surface ??= CreateBaseRuler (settings, preliminarySize);

// Draw the selection projection if a selection exists
if (selection_start.HasValue && selection_end.HasValue) {

// Convert selection coordinates to ruler widget coordinates
double p1 = GetPositionOnRuler (selection_start.Value, settings.EffectiveSize.Width);
double p2 = GetPositionOnRuler (selection_end.Value, settings.EffectiveSize.Width);

cr.SetSourceRgba ( // Semi-transparent blue
red: 0.21,
green: 0.52,
blue: 0.89,
alpha: 0.25);

switch (Orientation) {
case Gtk.Orientation.Horizontal:
cr.Rectangle (p1, 0, p2 - p1, settings.EffectiveSize.Height);
break;
default:
cr.Rectangle (0, p1, settings.EffectiveSize.Height, p2 - p1);
break;
}

cr.Fill ();
}

cr.SetSourceSurface (cached_surface, 0, 0);
cr.Paint ();

Expand Down Expand Up @@ -306,7 +346,7 @@ private ImageSurface CreateBaseRuler (in RulerDrawSettings settings, Size prelim

drawingContext.SetSourceColor (settings.Color);
drawingContext.LineWidth = 1.0;
drawingContext.Rectangle (settings.RulerBottomLine);
drawingContext.Rectangle (settings.RulerOuterLine);
drawingContext.Fill ();

for (int i = settings.Start; i <= settings.End; ++i) {
Expand Down Expand Up @@ -355,6 +395,15 @@ private ImageSurface CreateBaseRuler (in RulerDrawSettings settings, Size prelim
return result;
}

[MethodImpl (MethodImplOptions.AggressiveInlining)]
private double GetPositionOnRuler (double position, double width)
{
double range = Upper - Lower;
double scaledWidth = width / range;
double positionFromLower = position - Lower;
return positionFromLower * scaledWidth;
}

private static int GetFontSize (Pango.FontDescription font, int scaleFactor)
{
int fontSize = PangoExtensions.UnitsToPixels (font.GetSize ());
Expand Down
Loading