Skip to content

Commit

Permalink
DisplaySelector control better algorithm
Browse files Browse the repository at this point in the history
  • Loading branch information
rocksdanister committed Apr 27, 2024
1 parent 8b08c31 commit c626c81
Show file tree
Hide file tree
Showing 7 changed files with 97 additions and 154 deletions.
7 changes: 6 additions & 1 deletion src/Lively/Lively.UI.WinUI/UserControls/DisplaySelector.xaml
Expand Up @@ -78,6 +78,11 @@
Opacity="1"
Source="{Binding ScreenImagePath, Mode=OneWay}"
Stretch="UniformToFill" />
<TextBlock
HorizontalAlignment="Center"
VerticalAlignment="Center"
FontSize="12"
Text="{Binding ScreenTitle, Mode=OneWay}" />
<!-- Improve label visiblity -->
<Rectangle>
<Rectangle.Fill>
Expand Down Expand Up @@ -112,7 +117,7 @@
<TextBlock
Margin="2.5,-2.5,0,0"
FontSize="18"
Text="{Binding ScreenTitle, Mode=OneWay}" />
Text="{Binding Screen.Index, Mode=OneWay}" />
</Grid>
</DataTemplate>
</ItemsControl.ItemTemplate>
Expand Down
169 changes: 63 additions & 106 deletions src/Lively/Lively.UI.WinUI/UserControls/DisplaySelector.xaml.cs
Expand Up @@ -107,47 +107,85 @@ private void UpdateCanvas()
if (Displays is null || !Displays.Any() || !this.IsLoaded)
return;

switch (Layout)
switch (Displays.Count > 1 ? Layout : WallpaperArrangement.per)
{
case WallpaperArrangement.per:
{
DrawPerLayout();
var totalBounds = new Rectangle();
foreach (var item in Displays)
{
totalBounds = Rectangle.Union(totalBounds, item.Screen.Bounds);
}
int totalWidth = totalBounds.Width;
int totalHeight = totalBounds.Height;
// Worst case factor + margin
var factor = Math.Max(totalHeight / this.ActualHeight, totalWidth / this.ActualWidth) + 2;

// Normalize values, alternatively implement auto-scaling Canvas control.
foreach (var item in Displays)
{
item.NormalizedBounds = new Rectangle((int)(item.Screen.Bounds.Left / factor),
(int)(item.Screen.Bounds.Top / factor),
(int)(item.Screen.Bounds.Width / factor),
(int)(item.Screen.Bounds.Height / factor));
}
}
break;
case WallpaperArrangement.duplicate:
{
// Make it identical to per-screen
if (Displays.Count == 1)
DrawPerLayout();
else
DrawDuplicateLayout();
int sampleWidth = 1920;
int sampleHeight = 1080;
int offsetX = 150;
int offsetY = 150;
var totalBounds = new Rectangle();
// Creating fake display for presentation (overlapped.)
for (int i = 0; i < Displays.Count; i++)
{
var bounds = new Rectangle(offsetX * i, offsetY * i, sampleWidth, sampleHeight);
totalBounds = Rectangle.Union(totalBounds, bounds);
}
int totalWidth = totalBounds.Width;
int totalHeight = totalBounds.Height;
var factor = Math.Max(totalHeight / this.ActualHeight, totalWidth / this.ActualWidth) + 2;

for (int i = 0; i < Displays.Count; i++)
{
Displays[i].NormalizedBounds = new Rectangle((int)(offsetX * i / factor),
(int)(offsetY * i / factor),
(int)(sampleWidth / factor),
(int)(sampleHeight / factor));
}
}
break;
case WallpaperArrangement.span:
{
if (Displays.Count == 1)
DrawPerLayout();
else
DrawSpanLayout();
int sampleWidth = 1920;
int sampleHeight = 1080;
int offsetX = sampleWidth / 2;
int offsetY = 0;
var totalBounds = new Rectangle();
// Creating fake display for presentation (side by side.)
for (int i = 0; i < Displays.Count; i++)
{
var bounds = new Rectangle(offsetX * i, offsetY * i, sampleWidth, sampleHeight);
totalBounds = Rectangle.Union(totalBounds, bounds);
}
int totalWidth = totalBounds.Width;
int totalHeight = totalBounds.Height;
var factor = Math.Max(totalHeight / this.ActualHeight, totalWidth / this.ActualWidth) + 2;

for (int i = 0; i < Displays.Count; i++)
{
Displays[i].NormalizedBounds = new Rectangle((int)(offsetX * i / factor),
(int)(offsetY * i / factor),
(int)(sampleWidth / factor),
(int)(sampleHeight / factor));
}
}
break;
default:
throw new NotImplementedException();
}
}

private void DrawPerLayout()
{
// Normalize values
// Note: It is better to implement auto scaling canvas control instead in the future
int totalWidth = Displays.Sum(item => item.Screen.Bounds.Width);
int totalHeight = Displays.Sum(item => item.Screen.Bounds.Height);

foreach (var item in Displays)
{
var normalizedBounds = Normalize(item.Screen.Bounds, totalWidth, totalHeight);
item.NormalizedBounds = new Rectangle(normalizedBounds.Left, normalizedBounds.Top, normalizedBounds.Width, normalizedBounds.Height);
}

// Bounds.Left and Right can be negative
int minLeft = Displays.Min(item => item.NormalizedBounds.Left);
Expand All @@ -169,70 +207,6 @@ private void DrawPerLayout()
}
}

private void DrawDuplicateLayout()
{
// Normalize values
int sampleWidth = 1920;
int sampleHeight = 1080;
int totalWidth = sampleWidth * Displays.Count;
int totalHeight = sampleHeight * Displays.Count;

foreach (var item in Displays)
{
var normalizedBounds = Normalize(new Rectangle(0, 0, sampleWidth, sampleHeight), totalWidth, totalHeight);
item.NormalizedBounds = new Rectangle(normalizedBounds.Left, normalizedBounds.Top, normalizedBounds.Width, normalizedBounds.Height);
}

// Center to canvas
int normalizedTotalWidth = Displays[0].NormalizedBounds.Width + (int)(sampleWidth * Displays.Count * 0.01f);
int normalizedTotalHeight = Displays[0].NormalizedBounds.Height;
double horizontalOffset = this.ActualWidth / 2 - normalizedTotalWidth / 2;
double verticalOffset = this.ActualHeight / 2 - normalizedTotalHeight / 2;

for (int i = 0; i < Displays.Count; i++)
{
var item = Displays[i];
var allMargin = sampleWidth * i * 0.01f;
item.NormalizedBounds = new Rectangle(
(int)(item.NormalizedBounds.Left + horizontalOffset + allMargin),
(int)(item.NormalizedBounds.Top + verticalOffset + allMargin),
item.NormalizedBounds.Width,
item.NormalizedBounds.Height);
}
}

private void DrawSpanLayout()
{
// Normalize values
int sampleWidth = 1920;
int sampleHeight = 1080;
int totalWidth = sampleWidth * Displays.Count;
int totalHeight = sampleHeight * Displays.Count;

for (int i = 0; i < Displays.Count; i++)
{
var normalizedBounds = Normalize(new Rectangle(sampleWidth * i, 0, sampleWidth, sampleHeight), totalWidth, totalHeight);
Displays[i].NormalizedBounds = new Rectangle(normalizedBounds.Left, normalizedBounds.Top, normalizedBounds.Width, normalizedBounds.Height);
}

// Center to canvas
int normalizedTotalWidth = Displays.Sum(item => item.NormalizedBounds.Width) - (int)(Displays.Count * sampleWidth * 0.01f);
int normalizedTotalHeight = Displays.Max(item => item.NormalizedBounds.Height);
double horizontalOffset = this.ActualWidth / 2 - normalizedTotalWidth / 2;
double verticalOffset = this.ActualHeight / 2 - normalizedTotalHeight / 2;

for (int i = 0; i < Displays.Count; i++)
{
var item = Displays[i];
var leftMargin = -i * sampleWidth * 0.01f;
item.NormalizedBounds = new Rectangle(
(int)(item.NormalizedBounds.Left + horizontalOffset + leftMargin),
(int)(item.NormalizedBounds.Top + verticalOffset),
item.NormalizedBounds.Width,
item.NormalizedBounds.Height);
}
}

private void Displays_CollectionChanged(object sender, System.Collections.Specialized.NotifyCollectionChangedEventArgs e)
{
// Call the update methods whenever the collection changes
Expand Down Expand Up @@ -296,22 +270,5 @@ private void UserControl_Unloaded(object sender, RoutedEventArgs e)
//TODO: Unsubcribe Grid_PointerPressed().. ?
//TODO: Unsub CollectionChanged event ViewModel ?
}

private static Rectangle Normalize(Rectangle rect, int maxWidth, int maxHeight, int newMaxValue = 300)
{
int largerDimension = Math.Max(maxWidth, maxHeight);

double normalizedLeft = (double)rect.Left / largerDimension;
double normalizedTop = (double)rect.Top / largerDimension;
double normalizedWidth = (double)rect.Width / largerDimension;
double normalizedHeight = (double)rect.Height / largerDimension;

int left = (int)(normalizedLeft * newMaxValue);
int top = (int)(normalizedTop * newMaxValue);
int width = (int)(normalizedWidth * newMaxValue);
int height = (int)(normalizedHeight * newMaxValue);

return new Rectangle(left, top, width, height);
}
}
}
Expand Up @@ -61,7 +61,7 @@ private void UpdateLayout()
ScreenItems.Add(new ScreenLayoutModel(item,
string.IsNullOrEmpty(wallpaper?.PreviewPath) ? wallpaper?.ThumbnailPath : wallpaper.PreviewPath,
wallpaper?.LivelyPropertyCopyPath,
item.Index.ToString()));
string.Empty));
}
}

Expand Down
Expand Up @@ -2,6 +2,7 @@
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.ComponentModel;
using System.Drawing;
using System.IO;
using System.Linq;
using System.Threading.Tasks;
Expand Down Expand Up @@ -263,7 +264,7 @@ private void UpdateLayout()
ScreenItems.Add(new ScreenLayoutModel(item,
string.IsNullOrEmpty(wallpaper?.PreviewPath) ? wallpaper?.ThumbnailPath : wallpaper.PreviewPath,
wallpaper?.LivelyPropertyCopyPath,
item.Index.ToString()));
string.Empty));
}

SelectedItem = ScreenItems.FirstOrDefault(x => x.Screen.Equals(userSettings.Settings.SelectedDisplay));
Expand Down
4 changes: 2 additions & 2 deletions src/Lively/Lively.UI.WinUI/Views/Pages/ChooseDisplayView.xaml
Expand Up @@ -10,8 +10,8 @@


<Grid
Width="450"
Height="250"
Width="490"
Height="360"
Background="{ThemeResource ApplicationPageBackgroundThemeBrush}"
CornerRadius="5">
<customControls:DisplaySelector Displays="{Binding ScreenItems, Mode=OneWay}" SelectedItem="{Binding SelectedItem, Mode=TwoWay}" />
Expand Down
Expand Up @@ -39,30 +39,19 @@
IsSelection="False"
Layout="{Binding WallpaperLayout, Mode=OneWay}" />

<CommandBar
<!--<StackPanel
Grid.Row="1"
Margin="5"
HorizontalAlignment="Center"
DefaultLabelPosition="Right"
IsEnabled="false">
<AppBarButton
x:Uid="CustomiseWallpaper"
Command="{Binding CustomiseWallpaperCommand}"
LabelPosition="Collapsed"
Visibility="Visible">
<AppBarButton.Icon>
<FontIcon Glyph="&#xE790;" />
</AppBarButton.Icon>
</AppBarButton>
<AppBarSeparator Visibility="Visible" />
<AppBarButton
x:Uid="CloseWallpapers"
Command="{Binding CloseWallpaperCommand}"
LabelPosition="Collapsed">
<AppBarButton.Icon>
<FontIcon Glyph="&#xE894;" />
</AppBarButton.Icon>
</AppBarButton>
</CommandBar>
Orientation="Horizontal"
Spacing="5">
<Button Command="{Binding CustomiseWallpaperCommand}">
<FontIcon Glyph="&#xE790;" />
</Button>
<Button Command="{Binding CloseWallpaperCommand}">
<FontIcon Glyph="&#xE894;" />
</Button>
</StackPanel>-->

<Border Grid.RowSpan="2" Visibility="{Binding IsScreensaverPluginNotify, Mode=OneWay, Converter={StaticResource VisibilityConverter}}">
<Border.Background>
Expand Down
Expand Up @@ -39,28 +39,19 @@
Layout="{Binding SelectedWallpaperLayout, Mode=OneWay}"
SelectedItem="{Binding SelectedItem, Mode=TwoWay}" />

<CommandBar
<StackPanel
Grid.Row="1"
Margin="5"
HorizontalAlignment="Center"
DefaultLabelPosition="Right">
<AppBarButton
x:Uid="CustomiseWallpaper"
Command="{Binding CustomiseWallpaperCommand}"
LabelPosition="Collapsed">
<AppBarButton.Icon>
<FontIcon Glyph="&#xE790;" />
</AppBarButton.Icon>
</AppBarButton>
<AppBarSeparator Visibility="Visible" />
<AppBarButton
x:Uid="CloseWallpapers"
Command="{Binding CloseWallpaperCommand}"
LabelPosition="Collapsed">
<AppBarButton.Icon>
<FontIcon Glyph="&#xE894;" />
</AppBarButton.Icon>
</AppBarButton>
</CommandBar>
Orientation="Horizontal"
Spacing="5">
<Button Command="{Binding CustomiseWallpaperCommand}">
<FontIcon Glyph="&#xE790;" />
</Button>
<Button Command="{Binding CloseWallpaperCommand}">
<FontIcon Glyph="&#xE894;" />
</Button>
</StackPanel>
</Grid>

<controls:SettingsExpander
Expand All @@ -77,7 +68,7 @@
<controls:SegmentedItem>
<TextBlock>
<Run x:Uid="WallpaperLayoutPerScreen" />
<Run Foreground="{ThemeResource SystemAccentColorLight2}" Text="{Binding SelectedItem.ScreenTitle, Mode=OneWay, Converter={StaticResource StringFormatConverter}, ConverterParameter='({0})'}" />
<Run Foreground="{ThemeResource SystemAccentColorLight2}" Text="{Binding SelectedItem.Screen.Index, Mode=OneWay, Converter={StaticResource StringFormatConverter}, ConverterParameter='({0})'}" />
</TextBlock>
</controls:SegmentedItem>
<controls:SegmentedItem>
Expand Down

0 comments on commit c626c81

Please sign in to comment.