CG Library SkiaSharp「アイコン・ランチャー」

<B>
<font COLOR="blue" >
・------------------------------------------------------------------------------------・<BR>
・アイコン選択です。<BR>
・マウスが移動するとその区域の三角矢印が付き、またアンダーラインがひかれ<BR>
・どのアイコンを選択しているかわかる仕組み。よくあるやつです。<BR>
・SkiaSharpについては <a href="https://qiita.com/inf102/items/e6cc6d8590b929f5e54e">別記事参照</A><BR>
・------------------------------------------------------------------------------------・<BR>
</B>

Inceaceが選択されるている様子 
(画像は(c)コンポーネントソース社)
![1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2821882/5d6cbf7a-216a-7fd2-73df-d894df01ac95.png)
<iframe width="250" height="300" src="https://www.youtube.com/embed/E7aVplPTW-M" title="Menu sample (SkiaSharp) #wpf" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" allowfullscreen></iframe>

### <font  color="6495ed">1.解説</F>
丸型の場合はマウスが何処のアイコンを選択しているか判定するにはSin,Cosの三角関数を使用して全区域のXY値を調べる必要があります。


![B - コピー (2).jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2821882/786b7a46-3547-2b3e-6e00-aa41d3bb4ae4.jpeg)

この場合は8アイコンに分かれるのでそれぞれの区画の全XY値を取得。

・格納領域
```
// XY値格納
struct B1{
    public int x,y;
}
static B1[] BT1 = new B1[170000];
```

・8個の内の一つの区域の全XY値取得
x1,y1は円中心から40離れた所のXY値、更にx1,y1を円中心として円周上までのXY値を取得し構造体に格納。これを全8区画において実施。このサイズの場合はSin,Cosを計34万回計算するが瞬時に終わる。


```c#
for (int g=135;g<370;g++){

    x1=info.Width  / 2+40*Math.Sin(g*Math.PI/1000);
    y1=info.Height / 2-40*Math.Cos(g*Math.PI/1000);

    for (int h=1;h<90;h++){

        x2=x1+h*Math.Sin(g*Math.PI/1000);
        BT1[cc].x=(int)x2;

        y2=y1-h*Math.Cos(g*Math.PI/1000);
        BT1[cc].y=(int)y2;
        cc++;

        //  canvas.DrawPoint( (int)(x2),(int)y2,W_LINE);
                 
    }
}
```
下記画像の様にそれぞれのアイコンを選択されている画像を用意し、VSのResourceに入れておく。
(一枚にしておいてアンダーラインと三角矢印を描画する方法もある。その方がスマートではある)
1.png　"Resources/1.png"　x:Name="AAA"
![68747470733a2f2f71696974612d696d6167652d73746f72652e73332e61702d6e6f727468656173742d312e616d617a6f6e6177732e636f6d2f302f323832313838322f63663234353264652d323732662d313832362d326531382d6461383662623062646631652e706e67.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2821882/c9c20650-29fa-38cb-083b-8be1888ae1c9.png)

2.png　"Resources/2.png"　x:Name="BBB"
![68747470733a2f2f71696974612d696d6167652d73746f72652e73332e61702d6e6f727468656173742d312e616d617a6f6e6177732e636f6d2f302f323832313838322f37623630633133332d363035612d633038392d663730342d3934346563383032663835302e706e67.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2821882/daf46632-fc4d-7515-7199-2f271c202820.png)


XAMLでは、
```
        <Border>
            <Image x:Name="AAA" Source="Resources/1.png" Width="263" Height="263" />
        </Border>

        <Border>
            <Image x:Name="BBB" Source="Resources/2.png" Width="263" Height="263" />
        </Border>
```
・マウス移動イベントハンドラでマウスのXY値と先に格納したXY値と照合して該当する「アイコンが選択されている画像」を表示、その他を非表示にする。
```c#
private void skiaCanvas_MouseMove(object sender, System.Windows.Input.MouseEventArgs e) {

    // ローカルマウス位置
    System.Windows.Point point = e.GetPosition(this);
    int MY=(int)point.Y;
    int MX=(int)point.X;

    //1
    for (int f=0;f<=20700;f++){
        if (MY == BT1[f].y && MX == BT1[f].x ) {
            AAA.Visibility=Visibility.Visible;
            BBB.Visibility=Visibility.Hidden;
            CCC.Visibility=Visibility.Hidden;
            DDD.Visibility=Visibility.Hidden;
            EEE.Visibility=Visibility.Hidden;
            FFF.Visibility=Visibility.Hidden;
            GGG.Visibility=Visibility.Hidden;
            HHH.Visibility=Visibility.Hidden;
        }

     }
            
     //2
     for (int f=20700;f<=40000;f++){
         if (MY == BT1[f].y && MX == BT1[f].x ) {
             AAA.Visibility=Visibility.Hidden;
             CCC.Visibility=Visibility.Hidden;
             DDD.Visibility=Visibility.Hidden;
             BBB.Visibility=Visibility.Visible;
             EEE.Visibility=Visibility.Hidden;
             FFF.Visibility=Visibility.Hidden;
             GGG.Visibility=Visibility.Hidden;
             HHH.Visibility=Visibility.Hidden;
          }
    }
```

簡単にやるとしたら各アイコンの背景色を変えておいて(RGB値で1違うだけなら見た目わからない)マウスの場所の色を取得して判定する方法もある。こんな事を考えるのは自分位かも知れない。動作に問題なければそれで良いんです。ごまかし万歳です。

#### <font  color="6495ed">2.全ソースコード (WPF C#)</FONT>
```c#
/////////////////////////////////////////////////
// Menu,ランチャ WPF+SkiaSharp / (c)inf102 2023.
/////////////////////////////////////////////////

using SkiaSharp;
using SkiaSharp.Views.Desktop;
using System;
using System.Windows;

namespace WPF_CIRCLE_BTN {

    public partial class MainWindow : Window {
     
        public void m(string m){
            MessageBox.Show(m);
        }

        public MainWindow() {
            InitializeComponent();
            skiaCanvas.InvalidateVisual(); 
       }

        // XY値格納
        struct B1{
            public int x,y;

        }

        // 表示データ構造体配列
        static B1[] BT1 = new B1[170000];

        void PaintSurface(object sender, SKPaintSurfaceEventArgs args){

            SKImageInfo info = args.Info;
            SKSurface surface = args.Surface;
            SKCanvas canvas = surface.Canvas;
                   
            SKPaint W_LINE= new SKPaint{
	            Style =  SKPaintStyle.Stroke,
			    Color = new SKColor(0, 0,0),
                IsAntialias=true,
                StrokeWidth = 1

            };

            //////////////////////////////////////////////////
            // 冗長コードが続くため、メソッド化してください。
            // サンプルでそれをやると分かり辛くなるので止めてます。
            double x1,y1,x2,y2;
            int cc=0;

            // 1
            for (int g=135;g<370;g++){

                x1=info.Width  / 2+40*Math.Sin(g*Math.PI/1000);
                y1=info.Height / 2-40*Math.Cos(g*Math.PI/1000);

                for (int h=1;h<90;h++){

                    x2=x1+h*Math.Sin(g*Math.PI/1000);
                    BT1[cc].x=(int)x2;

                    y2=y1-h*Math.Cos(g*Math.PI/1000);
                    BT1[cc].y=(int)y2;
                    cc++;

                  //  canvas.DrawPoint( (int)(x2),(int)y2,W_LINE);
                 
                }
            }
      
            // 2
            for (int g=390;g<618;g++){

                x1=info.Width  / 2+40*Math.Sin(g*Math.PI/1000);
                y1=info.Height / 2-40*Math.Cos(g*Math.PI/1000);

                for (int h=1;h<90;h++){

                    x2=x1+h*Math.Sin(g*Math.PI/1000);
                    BT1[cc].x=(int)x2;

                    y2=y1-h*Math.Cos(g*Math.PI/1000);
                    BT1[cc].y=(int)y2;
                    cc++;

                 //   canvas.DrawPoint( (int)(x2),(int)y2,W_LINE);



                }

            }
                 
            // 3
            for (int g=637;g<866;g++){

                x1=info.Width  / 2+40*Math.Sin(g*Math.PI/1000);
                y1=info.Height / 2-40*Math.Cos(g*Math.PI/1000);

                for (int h=1;h<90;h++){

                    x2=x1+h*Math.Sin(g*Math.PI/1000);
                    BT1[cc].x=(int)x2;

                    y2=y1-h*Math.Cos(g*Math.PI/1000);
                    BT1[cc].y=(int)y2;
                    cc++;

                 //   canvas.DrawPoint( (int)(x2),(int)y2,W_LINE);
                }

            }      
            
            // 4
            for (int g=886;g<1114;g++){

                x1=info.Width  / 2+40*Math.Sin(g*Math.PI/1000);
                y1=info.Height / 2-40*Math.Cos(g*Math.PI/1000);

                for (int h=1;h<90;h++){

                    x2=x1+h*Math.Sin(g*Math.PI/1000);
                    BT1[cc].x=(int)x2;

                    y2=y1-h*Math.Cos(g*Math.PI/1000);
                    BT1[cc].y=(int)y2;
                    cc++;

                 //   canvas.DrawPoint( (int)(x2),(int)y2,W_LINE);
                }

            }      

            // 5
            for (int g=1134;g<1363;g++){

                x1=info.Width  / 2+40*Math.Sin(g*Math.PI/1000);
                y1=info.Height / 2-40*Math.Cos(g*Math.PI/1000);

                for (int h=1;h<90;h++){

                    x2=x1+h*Math.Sin(g*Math.PI/1000);
                    BT1[cc].x=(int)x2;

                    y2=y1-h*Math.Cos(g*Math.PI/1000);
                    BT1[cc].y=(int)y2;
                    cc++;

                 //   canvas.DrawPoint( (int)(x2),(int)y2,W_LINE);
                }

            }      
     
            // 6
            for (int g=1383;g<1615;g++){

                x1=info.Width  / 2+40*Math.Sin(g*Math.PI/1000);
                y1=info.Height / 2-40*Math.Cos(g*Math.PI/1000);

                for (int h=1;h<90;h++){

                    x2=x1+h*Math.Sin(g*Math.PI/1000);
                    BT1[cc].x=(int)x2;

                    y2=y1-h*Math.Cos(g*Math.PI/1000);
                    BT1[cc].y=(int)y2;
                    cc++;

                 //   canvas.DrawPoint( (int)(x2),(int)y2,W_LINE);
                }

            }      
     
            
            // 7
            for (int g=1630;g<1870;g++){

                x1=info.Width  / 2+40*Math.Sin(g*Math.PI/1000);
                y1=info.Height / 2-40*Math.Cos(g*Math.PI/1000);

                for (int h=1;h<90;h++){

                    x2=x1+h*Math.Sin(g*Math.PI/1000);
                    BT1[cc].x=(int)x2;

                    y2=y1-h*Math.Cos(g*Math.PI/1000);
                    BT1[cc].y=(int)y2;
                    cc++;

                  //  canvas.DrawPoint( (int)(x2),(int)y2,W_LINE);
                 
                }
            }

            // 8
            for (int g=1885;g<2120;g++){

                x1=info.Width  / 2+40*Math.Sin(g*Math.PI/1000);
                y1=info.Height / 2-40*Math.Cos(g*Math.PI/1000);

                for (int h=1;h<90;h++){

                    x2=x1+h*Math.Sin(g*Math.PI/1000);
                    BT1[cc].x=(int)x2;

                    y2=y1-h*Math.Cos(g*Math.PI/1000);
                    BT1[cc].y=(int)y2;
                    cc++;

                  //  canvas.DrawPoint( (int)(x2),(int)y2,W_LINE);
                 
                }
            }

          

        }

        // ここも適当にメソッド化して簡略化してください。
        private void skiaCanvas_MouseMove(object sender, System.Windows.Input.MouseEventArgs e) {

            // ローカルマウス位置
            System.Windows.Point point = e.GetPosition(this);
            int MY=(int)point.Y;
            int MX=(int)point.X;

            //1
            for (int f=0;f<=20700;f++){
                if (MY == BT1[f].y && MX == BT1[f].x ) {
                    AAA.Visibility=Visibility.Visible;
                    BBB.Visibility=Visibility.Hidden;
                    CCC.Visibility=Visibility.Hidden;
                    DDD.Visibility=Visibility.Hidden;
                    EEE.Visibility=Visibility.Hidden;
                    FFF.Visibility=Visibility.Hidden;
                    GGG.Visibility=Visibility.Hidden;
                    HHH.Visibility=Visibility.Hidden;
                }

            }

            //2
            for (int f=20700;f<=40000;f++){
                if (MY == BT1[f].y && MX == BT1[f].x ) {
                    AAA.Visibility=Visibility.Hidden;
                    CCC.Visibility=Visibility.Hidden;
                    DDD.Visibility=Visibility.Hidden;
                    BBB.Visibility=Visibility.Visible;
                    EEE.Visibility=Visibility.Hidden;
                    FFF.Visibility=Visibility.Hidden;
                    GGG.Visibility=Visibility.Hidden;
                    HHH.Visibility=Visibility.Hidden;
                }


            }

            //3
            for (int f=41500;f<=61800;f++){
                if (MY == BT1[f].y && MX == BT1[f].x ) {
                    CCC.Visibility=Visibility.Visible;
                    AAA.Visibility=Visibility.Hidden;
                    BBB.Visibility=Visibility.Hidden;
                    DDD.Visibility=Visibility.Hidden;
                    EEE.Visibility=Visibility.Hidden;
                    FFF.Visibility=Visibility.Hidden;
                    GGG.Visibility=Visibility.Hidden;
                    HHH.Visibility=Visibility.Hidden;
                }


            }


            //4
            for (int f=61800;f<=82000;f++){
                if (MY == BT1[f].y && MX == BT1[f].x ){
                    CCC.Visibility=Visibility.Hidden;
                    AAA.Visibility=Visibility.Hidden;
                    BBB.Visibility=Visibility.Hidden;
                    EEE.Visibility=Visibility.Hidden;
                    FFF.Visibility=Visibility.Hidden;
                    DDD.Visibility=Visibility.Visible;  
                    GGG.Visibility=Visibility.Hidden;
                    HHH.Visibility=Visibility.Hidden;

                }

            }


            //5
            for (int f=82100;f<=102500;f++){
                if (MY == BT1[f].y && MX == BT1[f].x ){
                    EEE.Visibility=Visibility.Visible;
                    BBB.Visibility=Visibility.Hidden;
                    CCC.Visibility=Visibility.Hidden;
                    DDD.Visibility=Visibility.Hidden;
                    GGG.Visibility=Visibility.Hidden;
                    AAA.Visibility=Visibility.Hidden;
                    FFF.Visibility=Visibility.Hidden;
                    HHH.Visibility=Visibility.Hidden;
                }

            }

      
            //6
            for (int f=102700;f<=123000;f++){
                if (MY == BT1[f].y && MX == BT1[f].x ){
                    EEE.Visibility=Visibility.Hidden;
                    BBB.Visibility=Visibility.Hidden;
                    CCC.Visibility=Visibility.Hidden;
                    DDD.Visibility=Visibility.Hidden;
                    GGG.Visibility=Visibility.Hidden;
                    AAA.Visibility=Visibility.Hidden;
                    FFF.Visibility=Visibility.Visible;
                    HHH.Visibility=Visibility.Hidden;


                }

            }
            
            //7
            for (int f=123000;f<=144200;f++){
                if (MY == BT1[f].y && MX == BT1[f].x ) {
                    AAA.Visibility=Visibility.Hidden;
                    BBB.Visibility=Visibility.Hidden;
                    CCC.Visibility=Visibility.Hidden;
                    DDD.Visibility=Visibility.Hidden;
                    EEE.Visibility=Visibility.Hidden;
                    FFF.Visibility=Visibility.Hidden;
                    GGG.Visibility=Visibility.Visible;
                    HHH.Visibility=Visibility.Hidden;
                }

            }

            //8
            for (int f=144500;f<=167700;f++){
                if (MY == BT1[f].y && MX == BT1[f].x ) {
                    AAA.Visibility=Visibility.Hidden;
                    BBB.Visibility=Visibility.Hidden;
                    CCC.Visibility=Visibility.Hidden;
                    DDD.Visibility=Visibility.Hidden;
                    EEE.Visibility=Visibility.Hidden;
                    FFF.Visibility=Visibility.Hidden;
                    GGG.Visibility=Visibility.Hidden;
                    HHH.Visibility=Visibility.Visible;
                }

            }
        }
    }
}
```
#### <font  color="6495ed">3.XAML</F>
```xml
<Window x:Class="WPF_CIRCLE_BTN.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        xmlns:local="clr-namespace:WPF_CIRCLE_BTN" xmlns:wpf="clr-namespace:SkiaSharp.Views.WPF;assembly=SkiaSharp.Views.WPF"
        mc:Ignorable="d"
        Title="MainWindow" Height="450" Width="450" >

    <Grid>
        <Border>
            <Image x:Name="AAA" Source="Resources/1.png" Width="263" Height="263" />
        </Border>

        <Border>
            <Image x:Name="BBB" Source="Resources/2.png" Width="263" Height="263" />
        </Border>

        <Border>
            <Image x:Name="CCC" Source="Resources/3.png" Width="263" Height="263" />
        </Border>

        <Border>
            <Image x:Name="DDD" Source="Resources/4.png" Width="263" Height="263" />
        </Border>

        <Border>
            <Image x:Name="EEE" Source="Resources/5.png" Width="263" Height="263" />
        </Border>

        <Border>
            <Image x:Name="FFF" Source="Resources/6.png" Width="263" Height="263" />
        </Border>


        <Border>
            <Image x:Name="GGG" Source="Resources/7.png" Width="263" Height="263" />
        </Border>

        <Border>
            <Image x:Name="HHH" Source="Resources/8.png" Width="263" Height="263" />
        </Border>
        
        <wpf:SKElement x:Name="skiaCanvas" PaintSurface="PaintSurface"  MouseMove="skiaCanvas_MouseMove"  />

    </Grid>
</Window>

```