public SelectRectangleViewModel() { MouseLeftDownPoint = new ReactivePropertySlim <RoixBorderPoint>(mode: ReactivePropertyMode.None); MouseLeftUpPoint = new ReactivePropertySlim <RoixBorderPoint>(mode: ReactivePropertyMode.None); MouseMovePoint = new ReactivePropertySlim <RoixBorderPoint>(); ViewBorderSize = new ReactivePropertySlim <RoixSize>(mode: ReactivePropertyMode.DistinctUntilChanged); SelectedRectangleToModel = new ReactivePropertySlim <RoixIntRect>(); var imageSourceSize = MyImage.ToRoixIntSize(); // 画像座標系の選択枠(これを基準に管理する) マウス操作中に枠を更新 + 操作完了時に枠位置を通知する var selectedRectangleOnImage = MouseMovePoint .Select(latestPoint => (startPoint: MouseLeftDownPoint.Value, latestPoint)) .Where(x => x.startPoint != x.latestPoint) .SkipUntil(MouseLeftDownPoint.ToUnit()) .TakeUntil(MouseLeftUpPoint.ToUnit()) .Finally(() => { var(startPoint, latestPoint) = (MouseLeftDownPoint.Value, MouseLeftUpPoint.Value); if (startPoint == default || latestPoint == default || startPoint == latestPoint) { return; } SelectedRectangleToModel.Value = RoixBorderIntRect.Create(startPoint, latestPoint, imageSourceSize).Roi; }) .Repeat() .Select(x => RoixBorderIntRect.Create(x.startPoint, x.latestPoint, imageSourceSize)) .ToReadOnlyReactivePropertySlim(); // View座標系の選択枠 SelectedRectangle = selectedRectangleOnImage .CombineLatest(ViewBorderSize, (rect, border) => rect.ConvertToNewBorder(border).Roi) .ToReadOnlyReactivePropertySlim(); }
/// <summary> /// コンストラクタ /// </summary> /// <param name="pokemonData"></param> public PokemonDetailVm(PokemonData pokemonData) : base(pokemonData) { DamageCalcVm = new ReactivePropertySlim <DamageCalcVm>(); UpdateFormSource(); ParameterCalculator.SetPokemon(pokemonData.Name, pokemonData.Form); Ev = new ParameterVm(new ParameterData <int>()); Iv = new ParameterVm(new ParameterData <int>(31, 31, 31, 31, 31, 31)); Param = new ParameterVm(new ParameterData <int>()); Personality = new ReactivePropertySlim <string>(string.Empty); Level = new ReactiveProperty <int>(50).AddTo(CompositeDisposable); ClipBoardParameter = new ReactiveProperty <string>(string.Empty); SetIvCommand = new DelegateCommand <string>(x => Iv.Model.Set(x)); SetEvCommand = new DelegateCommand <string>(x => Ev.Model.Set(x)); ChangePokemonCommand = new DelegateCommand <PokemonData>(x => { ChangePokemon(x.Name, x.Form); }); ShowDetailCommand = new DelegateCommand(() => Messenger.Raise(new TransitionMessage(new PokemonDetailVm(Model), "ShowDetail"))); NameWithSearchBox = new ReactiveProperty <string>(string.Empty).AddTo(CompositeDisposable); NameWithSearchBox.Subscribe(_ => ChangePokemon(_, null)).AddTo(CompositeDisposable); Observable.Merge( Ev.Model.PropertyChangedAsObservable().ToUnit(), Iv.Model.PropertyChangedAsObservable().ToUnit(), Personality.ToUnit(), Level.ToUnit()) .StartWith() .Throttle(TimeSpan.FromMilliseconds(50)) .ObserveOnDispatcher() .Do(_ => UpdateCalculator()) .Do(_ => UpdateFromParameter()) .Do(_ => GenerateClipBoardText()) .Subscribe() .AddTo(CompositeDisposable); Param.Model.PropertyChangedAsObservable() .StartWith() .Throttle(TimeSpan.FromMilliseconds(50)) .ObserveOnDispatcher() .Do(_ => UpdateFromParameter()) .Do(_ => GenerateClipBoardText()) .Subscribe() .AddTo(CompositeDisposable); // 努力値合計と残努力値の適用 TotalEv = Ev.Model .PropertyChangedAsObservable() .StartWith() .Select(x => Ev.Model.ToArray().Sum()) .Select(x => $"計{x}残{510 - x}") .ToReactiveProperty() .AddTo(CompositeDisposable); }
public SelectRectangleViewModel() { MouseDownPoint = new ReactivePropertySlim <Point>(mode: ReactivePropertyMode.None).AddTo(CompositeDisposable); MouseUpPoint = new ReactivePropertySlim <Point>(mode: ReactivePropertyMode.None).AddTo(CompositeDisposable); MouseMovePoint = new ReactivePropertySlim <Point>().AddTo(CompositeDisposable); ViewImageSize = new ReactivePropertySlim <Size>().AddTo(CompositeDisposable); IsFinishedSelectingRectangle = new ReactivePropertySlim <bool>().AddTo(CompositeDisposable); SelectedRectangle = new ReactivePropertySlim <Rect>().AddTo(CompositeDisposable); FixedRectangle = new ReactivePropertySlim <Rect>().AddTo(CompositeDisposable); // マウス操作中に移動量を流す + 操作完了時に枠位置を通知する MouseMovePoint .Select(movePoint => (startPoint: MouseDownPoint.Value, latestPoint: movePoint)) .SkipUntil(MouseDownPoint.ToUnit()) .TakeUntil(MouseUpPoint.ToUnit()) .Finally(() => { var(startPoint, latestPoint) = (MouseDownPoint.Value, MouseUpPoint.Value); if (startPoint == latestPoint) { return; } // 実画像の座標系に変換 var viewRect = ClipRectangle(new Rect(startPoint, latestPoint), ViewImageSize.Value); var imagePixelSize = new Size(MyImage.PixelWidth, MyImage.PixelHeight); var imagePixelRect = ConvertCoordinate(viewRect, ViewImageSize.Value, imagePixelSize); FixedRectangle.Value = imagePixelRect; IsFinishedSelectingRectangle.Value = true; }) .Repeat() .Subscribe(x => { SelectedRectangle.Value = ClipRectangle(new Rect(x.startPoint, x.latestPoint), ViewImageSize.Value); IsFinishedSelectingRectangle.Value = false; }) .AddTo(CompositeDisposable); // Viewのサイズ変更に枠サイズを追従 ViewImageSize .Pairwise() .Where(x => x.OldItem.Width != 0 && x.OldItem.Height != 0) .Select(x => (X: x.NewItem.Width / x.OldItem.Width, Y: x.NewItem.Height / x.OldItem.Height)) .Subscribe(ratio => SelectedRectangle.Value = MultipleRectangle(SelectedRectangle.Value, ratio.X, ratio.Y)) .AddTo(CompositeDisposable); }