diff --git a/App.xaml b/App.xaml
index 582a119..695ba23 100644
--- a/App.xaml
+++ b/App.xaml
@@ -23,6 +23,7 @@
+
diff --git a/Controls/AlignableWrapPanel.cs b/Controls/AlignableWrapPanel.cs
new file mode 100644
index 0000000..8851249
--- /dev/null
+++ b/Controls/AlignableWrapPanel.cs
@@ -0,0 +1,116 @@
+namespace LostArkTools.Controls;
+
+using System;
+using System.Windows;
+using System.Windows.Controls;
+
+public class AlignableWrapPanel : Panel
+{
+ public HorizontalAlignment HorizontalContentAlignment
+ {
+ get => (HorizontalAlignment)GetValue(HorizontalContentAlignmentProperty);
+ set => SetValue(HorizontalContentAlignmentProperty, value);
+ }
+
+ public static readonly DependencyProperty HorizontalContentAlignmentProperty =
+ DependencyProperty.Register("HorizontalContentAlignment", typeof(HorizontalAlignment), typeof(AlignableWrapPanel), new FrameworkPropertyMetadata(HorizontalAlignment.Left, FrameworkPropertyMetadataOptions.AffectsArrange));
+
+ protected override Size MeasureOverride(Size constraint)
+ {
+ var curLineSize = new Size();
+ var panelSize = new Size();
+
+ var children = InternalChildren;
+
+ for (var i = 0; i < children.Count; i++)
+ {
+ var child = children[i] as UIElement;
+
+ // Flow passes its own constraint to children
+ child.Measure(constraint);
+ var sz = child.DesiredSize;
+
+ if (curLineSize.Width + sz.Width > constraint.Width) //need to switch to another line
+ {
+ panelSize.Width = Math.Max(curLineSize.Width, panelSize.Width);
+ panelSize.Height += curLineSize.Height;
+ curLineSize = sz;
+
+ if (sz.Width > constraint.Width) // if the element is wider then the constraint - give it a separate line
+ {
+ panelSize.Width = Math.Max(sz.Width, panelSize.Width);
+ panelSize.Height += sz.Height;
+ curLineSize = new Size();
+ }
+ }
+ else //continue to accumulate a line
+ {
+ curLineSize.Width += sz.Width;
+ curLineSize.Height = Math.Max(sz.Height, curLineSize.Height);
+ }
+ }
+
+ // the last line size, if any need to be added
+ panelSize.Width = Math.Max(curLineSize.Width, panelSize.Width);
+ panelSize.Height += curLineSize.Height;
+
+ return panelSize;
+ }
+
+ protected override Size ArrangeOverride(Size arrangeBounds)
+ {
+ var firstInLine = 0;
+ var curLineSize = new Size();
+ double accumulatedHeight = 0;
+ var children = InternalChildren;
+
+ for (var i = 0; i < children.Count; i++)
+ {
+ var sz = children[i].DesiredSize;
+
+ if (curLineSize.Width + sz.Width > arrangeBounds.Width) //need to switch to another line
+ {
+ ArrangeLine(accumulatedHeight, curLineSize, arrangeBounds.Width, firstInLine, i);
+
+ accumulatedHeight += curLineSize.Height;
+ curLineSize = sz;
+
+ if (sz.Width > arrangeBounds.Width) //the element is wider then the constraint - give it a separate line
+ {
+ ArrangeLine(accumulatedHeight, sz, arrangeBounds.Width, i, ++i);
+ accumulatedHeight += sz.Height;
+ curLineSize = new Size();
+ }
+ firstInLine = i;
+ }
+ else //continue to accumulate a line
+ {
+ curLineSize.Width += sz.Width;
+ curLineSize.Height = Math.Max(sz.Height, curLineSize.Height);
+ }
+ }
+
+ if (firstInLine < children.Count)
+ ArrangeLine(accumulatedHeight, curLineSize, arrangeBounds.Width, firstInLine, children.Count);
+
+ return arrangeBounds;
+ }
+
+ private void ArrangeLine(double y, Size lineSize, double boundsWidth, int start, int end)
+ {
+ var x = HorizontalContentAlignment switch
+ {
+ HorizontalAlignment.Center => (boundsWidth - lineSize.Width) / 2,
+ HorizontalAlignment.Right => (boundsWidth - lineSize.Width),
+ _ => 0
+ };
+
+ var children = InternalChildren;
+ for (var i = start; i < end; i++)
+ {
+ var child = children[i];
+ child.Arrange(new Rect(x, y, child.DesiredSize.Width, lineSize.Height));
+ x += child.DesiredSize.Width;
+ }
+ }
+}
\ No newline at end of file
diff --git a/Converters/IsLastItemInContainerConverter.cs b/Converters/IsLastItemInContainerConverter.cs
new file mode 100644
index 0000000..078fe69
--- /dev/null
+++ b/Converters/IsLastItemInContainerConverter.cs
@@ -0,0 +1,25 @@
+using System;
+using System.Globalization;
+using System.Windows;
+using System.Windows.Controls;
+using System.Windows.Data;
+
+namespace LostArkTools.Converters;
+
+public class IsLastItemInContainerConverter : IValueConverter
+{
+ public object Convert(object value, Type targetType,
+ object parameter, CultureInfo culture)
+ {
+ var item = (DependencyObject)value;
+ var ic = ItemsControl.ItemsControlFromItemContainer(item);
+ var index = ic.ItemContainerGenerator.IndexFromContainer(item);
+ return index == ic.Items.Count - 1;
+ }
+
+ public object ConvertBack(object value, Type targetType,
+ object parameter, CultureInfo culture)
+ {
+ throw new NotImplementedException();
+ }
+}
\ No newline at end of file
diff --git a/Features/Checklist/CharacterChecklist/CharacterView.xaml b/Features/Checklist/CharacterChecklist/CharacterView.xaml
index e3e22fd..0589404 100644
--- a/Features/Checklist/CharacterChecklist/CharacterView.xaml
+++ b/Features/Checklist/CharacterChecklist/CharacterView.xaml
@@ -63,6 +63,7 @@
KeyUp="{s:Action CharacterNameKeyPressed}"
Margin="5" />
diff --git a/Features/ServerStatus/RegionView.xaml b/Features/ServerStatus/RegionView.xaml
index 3badd24..9e5771a 100644
--- a/Features/ServerStatus/RegionView.xaml
+++ b/Features/ServerStatus/RegionView.xaml
@@ -4,54 +4,50 @@
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:local="clr-namespace:LostArkTools.Features.ServerStatus"
+ xmlns:controls="clr-namespace:LostArkTools.Controls"
mc:Ignorable="d"
d:DataContext="{d:DesignInstance local:RegionViewModel}"
d:DesignHeight="300" d:DesignWidth="300">
-
-
-
-
+
+
+
+
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+ Grid.Column="1">
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/Features/ServerStatus/ServerStatusView.xaml b/Features/ServerStatus/ServerStatusView.xaml
index 3bfbcad..c3dd651 100644
--- a/Features/ServerStatus/ServerStatusView.xaml
+++ b/Features/ServerStatus/ServerStatusView.xaml
@@ -1,39 +1,40 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+ xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
+ xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
+ xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
+ xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
+ xmlns:local="clr-namespace:LostArkTools.Features.ServerStatus"
+ xmlns:s="https://github.com/canton7/Stylet"
+ mc:Ignorable="d"
+ d:DataContext="{d:DesignInstance local:ServerStatusViewModel}"
+ d:DesignHeight="300" d:DesignWidth="300">
+
+
+
+
+
+
+
+
-
-
-
-
-
-
-
-
-
-
+ Margin="5 10 5 10" />
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file