Commit 28513f53 authored by shrabbit's avatar shrabbit
Browse files

主界面和设置

parent a3a1030b
Loading
Loading
Loading
Loading
+36 −25
Original line number Diff line number Diff line
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.ComponentModel;
using System.Runtime.CompilerServices;
using System.Windows.Media;
@@ -8,98 +9,108 @@ namespace WatermarkClock
    public class Context : INotifyPropertyChanged
    {
        private string _output;

        public string Output
        {
            get => _output;
            set
            {
                if (SetField(ref _output, value))
                {
                    OnPropertyChanged();
            }
        }
        }

        private MarkPosition _pos;

        public MarkPosition MarkPosition
        {
            get => _pos;
            set
            {
                if (SetField(ref _pos, value))
                {
                    OnPropertyChanged();
            }
        }
        }

        private int _padding;

        private int _padding = 16;
        public int Padding
        {
            get => _padding;
            set
            {
                if (SetField(ref _padding, value))
                {
                    OnPropertyChanged();
            }
        }
        }

        private Brush _textBrs;

        private Brush _textBrs = Brushes.White;
        public Brush TextBrush
        {
            get => _textBrs;
            set
            {
                if (SetField(ref _textBrs, value))
                {
                    OnPropertyChanged();
            }
        }
        }

        private double _fontSize = 28;

        public double FontSize
        {
            get => _fontSize;
            set
            {
                if (SetField(ref _fontSize, value))
                {
                    OnPropertyChanged();
            }
        }
        }

        private Brush _olBrs;

        public Brush OutlineBrush
        {
            get => _textBrs;
            set
            {
                if (SetField(ref _textBrs, value))
                    OnPropertyChanged();
            }
        }

        private string _textColor = "#FFFFFF";
        public string TextColor
        {
            get => _textColor;
            set
            {
                if (SetField(ref _textColor, value))
                {
                    OnPropertyChanged();
                    try
                    {
                        var color = (Color)ColorConverter.ConvertFromString(value);
                        TextBrush = new SolidColorBrush(color);
                    }
                    catch { }
                }
            }
        }

        private int _refreshInterval = 16;
        public int RefreshInterval
        {
            get => _refreshInterval;
            set
            {
                if (SetField(ref _refreshInterval, value))
                    OnPropertyChanged();
            }
        }

        public ObservableCollection<TemplateItem> Templates { get; } = new ObservableCollection<TemplateItem>();

        #region NOTIFY

        public event PropertyChangedEventHandler PropertyChanged;

        protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null)
        {
            PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
        }

            => PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
        protected bool SetField<T>(ref T field, T value, [CallerMemberName] string propertyName = null)
        {
            if (EqualityComparer<T>.Default.Equals(field, value)) return false;
+81 −3
Original line number Diff line number Diff line
@@ -5,8 +5,86 @@
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        xmlns:local="clr-namespace:WatermarkClock"
        mc:Ignorable="d"
        Title="WatermarkClock - shRabbit" Height="350" Width="525">
        Title="WatermarkClock - shRabbit" Height="500" Width="520"
        ResizeMode="CanResize">
    <Grid Margin="12">
        <Grid.RowDefinitions>
            <RowDefinition Height="Auto"/>
            <RowDefinition Height="*"/>
            <RowDefinition Height="Auto"/>
        </Grid.RowDefinitions>

        <!-- 设置区域 -->
        <GroupBox Header="设置" Grid.Row="0" Padding="8">
            <Grid>
                <Grid.RowDefinitions>
                    <RowDefinition Height="Auto"/>
                    <RowDefinition Height="Auto"/>
                    <RowDefinition Height="Auto"/>
                    <RowDefinition Height="Auto"/>
                    <RowDefinition Height="Auto"/>
                </Grid.RowDefinitions>
                <Grid.ColumnDefinitions>
                    <ColumnDefinition Width="90"/>
                    <ColumnDefinition Width="*"/>
                </Grid.ColumnDefinitions>

                <TextBlock Text="位置:" VerticalAlignment="Center" Grid.Row="0"/>
                <ComboBox x:Name="CbPosition" Grid.Row="0" Grid.Column="1" Margin="0,4"
                          SelectedIndex="1"/>

                <TextBlock Text="边距:" VerticalAlignment="Center" Grid.Row="1"/>
                <TextBox x:Name="TbPadding" Grid.Row="1" Grid.Column="1" Margin="0,4" Text="16"/>

                <TextBlock Text="字体大小:" VerticalAlignment="Center" Grid.Row="2"/>
                <TextBox x:Name="TbFontSize" Grid.Row="2" Grid.Column="1" Margin="0,4" Text="28"/>

                <TextBlock Text="文字颜色:" VerticalAlignment="Center" Grid.Row="3"/>
                <TextBox x:Name="TbTextColor" Grid.Row="3" Grid.Column="1" Margin="0,4" Text="#FFFFFF"/>

                <TextBlock Text="刷新间隔:" VerticalAlignment="Center" Grid.Row="4"/>
                <StackPanel Orientation="Horizontal" Grid.Row="4" Grid.Column="1" Margin="0,4">
                    <TextBox x:Name="TbRefreshInterval" Width="80" Text="16"/>
                    <TextBlock Text="ms" VerticalAlignment="Center" Margin="4,0,0,0"/>
                </StackPanel>
            </Grid>
        </GroupBox>

        <!-- 模板列表 -->
        <GroupBox Header="模板列表(支持变量:{DatetimeF} {year} {month} {Day} {Hour} {Minute} {Second} {Week} 等)" Grid.Row="1" Margin="0,8,0,0" Padding="8">
            <Grid>
                <Grid.RowDefinitions>
                    <RowDefinition Height="*"/>
                    <RowDefinition Height="Auto"/>
                </Grid.RowDefinitions>

                <DataGrid x:Name="DgTemplates" Grid.Row="0"
                          AutoGenerateColumns="False"
                          CanUserAddRows="False"
                          CanUserDeleteRows="False"
                          SelectionMode="Single"
                          HeadersVisibility="Column">
                    <DataGrid.Columns>
                        <DataGridTextColumn Header="模板文本" Width="*"
                                            Binding="{Binding Text, UpdateSourceTrigger=PropertyChanged}"/>
                        <DataGridTextColumn Header="显示时长(秒)" Width="100"
                                            Binding="{Binding DurationSeconds, UpdateSourceTrigger=PropertyChanged}"/>
                    </DataGrid.Columns>
                </DataGrid>

                <StackPanel Orientation="Horizontal" Grid.Row="1" Margin="0,6,0,0">
                    <Button Content="添加" Width="60" Margin="0,0,4,0" Click="BtnAddTemplate_Click"/>
                    <Button Content="删除" Width="60" Margin="0,0,4,0" Click="BtnRemoveTemplate_Click"/>
                    <Button Content="上移" Width="60" Margin="0,0,4,0" Click="BtnMoveUp_Click"/>
                    <Button Content="下移" Width="60" Click="BtnMoveDown_Click"/>
                </StackPanel>
            </Grid>
        </GroupBox>

        <!-- 底部按钮 -->
        <StackPanel Orientation="Horizontal" Grid.Row="2" HorizontalAlignment="Right" Margin="0,8,0,0">
            <Button Content="应用" Width="80" Margin="0,0,8,0" Click="BtnApply_Click"/>
            <Button Content="隐藏到托盘" Width="90" Click="BtnHide_Click"/>
        </StackPanel>
    </Grid>
</Window>
+193 −23
Original line number Diff line number Diff line
using System;
using System.Windows.Media;
using System.Linq;
using System.Windows;
using System.Windows.Threading;
using WatermarkClock.Templates;

namespace WatermarkClock
{
    /// <summary>
    /// Interaction logic for MainWindow.xaml
    /// </summary>
    public partial class MainWindow
    {
        private readonly Context _ctx;
        private WatermarkClockWindow _watermarkWindow;
        private DispatcherTimer _refreshTimer;
        private DispatcherTimer _rotationTimer;
        private int _currentTemplateIndex;
        private NotifyIconWrapper _notifyIcon;

        public MainWindow()
        {
            var ctx = new Context()
            InitializeComponent();

            _ctx = new Context();
            InitComboBox();
            LoadDefaults();
            DgTemplates.ItemsSource = _ctx.Templates;

            _notifyIcon = new NotifyIconWrapper(this);
            ApplySettings();
        }

        private void InitComboBox()
        {
            CbPosition.ItemsSource = Enum.GetValues(typeof(MarkPosition));
            CbPosition.SelectedIndex = 1;
        }

        private void LoadDefaults()
        {
                MarkPosition = MarkPosition.TopRight,
                Output = "Hello",
                Padding = 16,
                TextBrush = Brushes.White,
                FontSize = 28
            _ctx.Templates.Add(new TemplateItem("{DatetimeF}", 10));
            TbPadding.Text = "16";
            TbFontSize.Text = "28";
            TbTextColor.Text = "#FFFFFF";
            TbRefreshInterval.Text = "16";
        }

        private void ApplySettings()
        {
            // 解析设置值
            if (CbPosition.SelectedItem is MarkPosition pos)
                _ctx.MarkPosition = pos;

            if (int.TryParse(TbPadding.Text, out var padding))
                _ctx.Padding = padding;

            if (double.TryParse(TbFontSize.Text, out var fontSize))
                _ctx.FontSize = fontSize;

            _ctx.TextColor = TbTextColor.Text;

            if (int.TryParse(TbRefreshInterval.Text, out var refreshMs) && refreshMs > 0)
                _ctx.RefreshInterval = refreshMs;

            // 创建/更新水印窗口
            if (_watermarkWindow == null)
            {
                _watermarkWindow = new WatermarkClockWindow(_ctx);
                _watermarkWindow.Show();
            }

            // 重启刷新定时器
            StartRefreshTimer();

            // 重启轮换定时器
            StartRotationTimer();
        }

        private void StartRefreshTimer()
        {
            _refreshTimer?.Stop();
            _refreshTimer = new DispatcherTimer
            {
                Interval = TimeSpan.FromMilliseconds(_ctx.RefreshInterval)
            };
            _refreshTimer.Tick += OnRefreshTick;
            _refreshTimer.Start();
        }

        private void StartRotationTimer()
        {
            _rotationTimer?.Stop();

            var dt = new DispatcherTimer
            if (_ctx.Templates.Count <= 1)
            {
                Interval = TimeSpan.FromMilliseconds(16)
            };dt.Start();
                // 单模板直接渲染
                _currentTemplateIndex = 0;
                RenderCurrentTemplate();
                return;
            }

            // 先渲染当前模板
            RenderCurrentTemplate();
            ScheduleNextRotation();
        }

            dt.Tick += (_1, _2) =>
        private void ScheduleNextRotation()
        {
                ctx.Output = new TextTemplateEngine()
            _rotationTimer?.Stop();

            if (_ctx.Templates.Count == 0) return;

            var currentItem = _ctx.Templates[_currentTemplateIndex];
            _rotationTimer = new DispatcherTimer
            {
                    Templates = { new BaseTime() }
                }.Replace("{DatetimeF}");
                Interval = TimeSpan.FromSeconds(currentItem.DurationSeconds)
            };
            _rotationTimer.Tick += OnRotationTick;
            _rotationTimer.Start();
        }

            InitializeComponent();
            new WatermarkClockWindow(ctx).Show();
        private void OnRefreshTick(object sender, EventArgs e)
        {
            RenderCurrentTemplate();
        }

        private void OnRotationTick(object sender, EventArgs e)
        {
            if (_ctx.Templates.Count == 0) return;

            _currentTemplateIndex = (_currentTemplateIndex + 1) % _ctx.Templates.Count;
            RenderCurrentTemplate();
            ScheduleNextRotation();
        }

        private void RenderCurrentTemplate()
        {
            if (_ctx.Templates.Count == 0)
            {
                _ctx.Output = "";
                return;
            }

            var template = _ctx.Templates[_currentTemplateIndex].Text;
            var engine = new TextTemplateEngine
            {
                Templates = { new BaseTime(), new BaseFunc() }
            };
            _ctx.Output = engine.Replace(template);
        }

        private void BtnApply_Click(object sender, RoutedEventArgs e)
        {
            ApplySettings();
        }

        private void BtnAddTemplate_Click(object sender, RoutedEventArgs e)
        {
            _ctx.Templates.Add(new TemplateItem("{DatetimeF}", 10));
        }

        private void BtnRemoveTemplate_Click(object sender, RoutedEventArgs e)
        {
            if (DgTemplates.SelectedItem is TemplateItem item)
            {
                var idx = _ctx.Templates.IndexOf(item);
                _ctx.Templates.Remove(item);
                if (_currentTemplateIndex >= _ctx.Templates.Count)
                    _currentTemplateIndex = 0;
                if (_ctx.Templates.Count > 0)
                    StartRotationTimer();
            }
        }

        private void BtnMoveUp_Click(object sender, RoutedEventArgs e)
        {
            if (!(DgTemplates.SelectedItem is TemplateItem item)) return;
            var idx = _ctx.Templates.IndexOf(item);
            if (idx <= 0) return;
            _ctx.Templates.Move(idx, idx - 1);
            DgTemplates.SelectedIndex = idx - 1;
        }

        private void BtnMoveDown_Click(object sender, RoutedEventArgs e)
        {
            if (!(DgTemplates.SelectedItem is TemplateItem item)) return;
            var idx = _ctx.Templates.IndexOf(item);
            if (idx >= _ctx.Templates.Count - 1) return;
            _ctx.Templates.Move(idx, idx + 1);
            DgTemplates.SelectedIndex = idx + 1;
        }

        private void BtnHide_Click(object sender, RoutedEventArgs e)
        {
            Hide();
        }

        protected override void OnClosed(EventArgs e)
        {
            _refreshTimer?.Stop();
            _rotationTimer?.Stop();
            _notifyIcon?.Dispose();
            _watermarkWindow?.Close();
            base.OnClosed(e);
        }

        public void ShowFromTray()
        {
            Show();
            Activate();
        }
    }
}
+4 −0
Original line number Diff line number Diff line
@@ -38,6 +38,8 @@
        <Reference Include="System"/>
        <Reference Include="System.Core"/>
        <Reference Include="System.Data"/>
        <Reference Include="System.Drawing"/>
        <Reference Include="System.Windows.Forms"/>
        <Reference Include="System.Xml"/>
        <Reference Include="System.Xaml">
            <RequiredTargetFramework>4.0</RequiredTargetFramework>
@@ -54,6 +56,8 @@
        <Compile Include="Context.cs" />
        <Compile Include="ITextTemplate.cs" />
        <Compile Include="MarkPosition.cs" />
        <Compile Include="NotifyIconWrapper.cs" />
        <Compile Include="TemplateItem.cs" />
        <Compile Include="Templates\BaseFunc.cs" />
        <Compile Include="Templates\BaseTime.cs" />
        <Compile Include="TextTemplateEngine.cs" />
+1 −0
Original line number Diff line number Diff line
@@ -57,6 +57,7 @@ namespace WatermarkClock
                case nameof(_context.MarkPosition):
                {
                    ChangePosition();
                    ChangePadding();
                    return;
                }