Browse Source

add frmMain

liuyuqi-dellpc 7 months ago
parent
commit
dab7759ef3

+ 26 - 0
TaskbarGroups/Models/BaseModel.cs

@@ -0,0 +1,26 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace TaskbarGroups.Models
+{
+    /// <summary>
+    /// base model
+    /// </summary>
+    class BaseModel
+    {
+        
+        public BaseModel()
+        {
+            this.Id = Guid.NewGuid();
+        }
+
+        public Guid Id { get; set; }
+
+
+        
+
+    }
+}

+ 33 - 0
TaskbarGroups/Models/Category.cs

@@ -0,0 +1,33 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Text.RegularExpressions;
+using System.Threading.Tasks;
+
+namespace TaskbarGroups.Models
+{
+    /// <summary>
+    /// 应用分类
+    /// </summary>
+    class Category
+    {
+
+        public Guid Id { get; set; }
+        private static readonly int[] iconSize = { 16, 32, 48, 256, 512 };
+        private readonly Regex specialCharRegex = new Regex("[^a-zA-Z0-9\u4e00-\u9fa5]+", RegexOptions.Compiled);
+
+        /// <summary>
+        /// 
+        /// </summary>
+        /// <param name="path">分组配置文件</param>
+        public Category(string path)
+        {
+            this.Id = Guid.NewGuid();
+        }
+
+
+
+    }
+}
+

+ 18 - 0
TaskbarGroups/NativeMethods/Kernel32.cs

@@ -0,0 +1,18 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Runtime.InteropServices;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace TaskbarGroups.NativeMethods
+{   
+    /// <summary>
+    /// 
+    /// </summary>
+    class Kernel32
+    {
+        [DllImport("kernel32.dll")]
+        public static extern IntPtr OpenProcess(uint dwDesiredAccess, bool bInheritHandle, int dwProcessId);
+    }
+}

+ 21 - 0
TaskbarGroups/NativeMethods/Shell32.cs

@@ -0,0 +1,21 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Runtime.InteropServices;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace TaskbarGroups.NativeMethods
+{
+    class Shell32
+    {
+        /// <summary>
+        /// 为当前进程设置一个明确的应用程序用户模型 ID
+        /// </summary>
+        /// <param name="AppID"></param>
+        [DllImport("shell32.dll", SetLastError = true)]
+        public static extern void SetCurrentProcessExplicitAppUserModelID([MarshalAs(UnmanagedType.LPWStr)] string AppID);
+
+
+    }
+}

+ 16 - 0
TaskbarGroups/NativeMethods/User32.cs

@@ -0,0 +1,16 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+using System.Runtime.InteropServices;
+
+namespace TaskbarGroups.NativeMethods
+{
+    class User32
+    {
+        [DllImport("user32.dll", SetLastError = true)]
+        public static extern IntPtr FindWindow(string lpClassName, string lpWindowName);
+        
+    }
+}

+ 11 - 4
TaskbarGroups/Pages/frmMain.Designer.cs

@@ -1,7 +1,8 @@
 
 namespace TaskbarGroups
 {
-    partial class frmMain
+
+    sealed partial class frmMain
     {
         /// <summary>
         /// Required designer variable.
@@ -33,12 +34,18 @@ namespace TaskbarGroups
             // 
             // frmMain
             // 
-            this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 12F);
+            this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
             this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
-            this.ClientSize = new System.Drawing.Size(800, 450);
+            this.BackColor = System.Drawing.Color.FromArgb(((int)(((byte)(33)))), ((int)(((byte)(33)))), ((int)(((byte)(33)))));
+            this.ClientSize = new System.Drawing.Size(325, 226);
+            this.DoubleBuffered = true;
+            this.KeyPreview = true;
             this.Name = "frmMain";
-            this.Text = "Form1";
+            this.Text = "Group";
+            this.Deactivate += new System.EventHandler(this.frmMain_Deactivate);
             this.Load += new System.EventHandler(this.frmMain_Load);
+            this.KeyDown += new System.Windows.Forms.KeyEventHandler(this.frmMain_KeyDown);
+            this.KeyUp += new System.Windows.Forms.KeyEventHandler(this.frmMain_KeyUp);
             this.ResumeLayout(false);
 
         }

+ 459 - 7
TaskbarGroups/Pages/frmMain.cs

@@ -1,28 +1,480 @@
 using System;
 using System.Collections.Generic;
-using System.ComponentModel;
-using System.Data;
 using System.Drawing;
-using System.Linq;
-using System.Text;
-using System.Threading.Tasks;
 using System.Windows.Forms;
 
 namespace TaskbarGroups
 {
+    /// <summary>
+    /// 主界面
+    /// </summary>
     public partial class frmMain : Form
     {
         private readonly string passedDirec;
-        //public List<ucShortcut> ControlList;
-        
+        public List<ucShortcut> ControlList;
+        public Color HoverColor;
+        public Point mouseClick;
+        public Panel shortcutPanel;
+        public PictureBox shortcutPic;
+
+        public Category ThisCategory;
+
         public frmMain()
         {
             InitializeComponent();
         }
 
+        public frmMain(string passedDirectory, int cursorPosX, int cursorPosY)
+        {
+            InitializeComponent();
+
+            ProfileOptimization.StartProfile("frmMain.Profile");
+            mouseClick = new Point(cursorPosX, cursorPosY); // Consstruct point p based on passed x y mouse values
+            passedDirec = passedDirectory;
+            FormBorderStyle = FormBorderStyle.None;
+
+            using (var ms = new MemoryStream(File.ReadAllBytes(MainPath.path + "\\config\\" + passedDirec + "\\GroupIcon.ico")))
+            {
+                Icon = new Icon(ms);
+            }
+
+            if (Directory.Exists(MainPath.path + @"\config\" + passedDirec))
+            {
+                ControlList = new List<ucShortcut>();
+
+                SetStyle(ControlStyles.SupportsTransparentBackColor, true);
+                ThisCategory = new Category($"config\\{passedDirec}");
+                BackColor = ImageFunctions.FromString(ThisCategory.ColorString);
+                Opacity = 1 - ThisCategory.Opacity / 100;
+
+                HoverColor = BackColor.R * 0.2126 + BackColor.G * 0.7152 + BackColor.B * 0.0722 > 255 / 2
+                    ? Color.FromArgb(BackColor.A, BackColor.R - 50, BackColor.G - 50, BackColor.B - 50)
+                    : Color.FromArgb(BackColor.A, BackColor.R + 50, BackColor.G + 50, BackColor.B + 50);
+            }
+            else
+                Application.Exit();
+        }
+
+        // Allow doubleBuffering drawing each frame to memory and then onto screen
+        // Solves flickering issues mostly as the entire rendering of the screen is done in 1 operation after being first loaded to memory
+        protected override CreateParams CreateParams
+        {
+            get
+            {
+                var cp = base.CreateParams;
+                cp.ExStyle |= 0x02000000;
+                return cp;
+            }
+        }
+
         private void frmMain_Load(object sender, EventArgs e)
         {
+            LoadCategory();
+            SetLocation();
+        }
+
+        // Sets location of form
+        private void SetLocation()
+        {
+            var taskbarList = FindDockedTaskBars();
+            var taskbar = new Rectangle();
+            var screen = new Rectangle();
+
+            var i = 0;
+            int locationy;
+            int locationx;
+            if (taskbarList.Count != 0)
+            {
+                foreach (var scr in Screen.AllScreens) // Get what screen user clicked on
+                {
+                    if (scr.Bounds.Contains(mouseClick))
+                    {
+                        screen.X = scr.Bounds.X;
+                        screen.Y = scr.Bounds.Y;
+                        screen.Width = scr.Bounds.Width;
+                        screen.Height = scr.Bounds.Height;
+                        taskbar = taskbarList[i];
+                    }
+
+                    i++;
+                }
+
+                if (taskbar.Contains(mouseClick)) // Click on taskbar
+                {
+                    if (taskbar.Top == screen.Top && taskbar.Width == screen.Width)
+                    {
+                        // TOP
+                        locationy = screen.Y + taskbar.Height + 10;
+                        locationx = mouseClick.X - Width / 2;
+                    }
+                    else if (taskbar.Bottom == screen.Bottom && taskbar.Width == screen.Width)
+                    {
+                        // BOTTOM
+                        locationy = screen.Y + screen.Height - Height - taskbar.Height - 10;
+                        locationx = mouseClick.X - Width / 2;
+                    }
+                    else if (taskbar.Left == screen.Left)
+                    {
+                        // LEFT
+                        locationy = mouseClick.Y - Height / 2;
+                        locationx = screen.X + taskbar.Width + 10;
+                    }
+                    else
+                    {
+                        // RIGHT
+                        locationy = mouseClick.Y - Height / 2;
+                        locationx = screen.X + screen.Width - Width - taskbar.Width - 10;
+                    }
+                }
+                else // not click on taskbar
+                {
+                    locationy = mouseClick.Y - Height - 20;
+                    locationx = mouseClick.X - Width / 2;
+                }
+
+                Location = new Point(locationx, locationy);
+
+                // If form goes over screen edge
+                if (Left < screen.Left)
+                    Left = screen.Left + 10;
+                if (Top < screen.Top)
+                    Top = screen.Top + 10;
+                if (Right > screen.Right)
+                    Left = screen.Right - Width - 10;
+
+                // If form goes over taskbar
+                if (taskbar.Contains(Left, Top) && taskbar.Contains(Right, Top)) // Top taskbar
+                    Top = screen.Top + 10 + taskbar.Height;
+                if (taskbar.Contains(Left, Top)) // Left taskbar
+                    Left = screen.Left + 10 + taskbar.Width;
+                if (taskbar.Contains(Right, Top)) // Right taskbar
+                    Left = screen.Right - Width - 10 - taskbar.Width;
+            }
+            else // Hidden taskbar
+            {
+                foreach (var scr in Screen.AllScreens) // get what screen user clicked on
+                {
+                    if (scr.Bounds.Contains(mouseClick))
+                    {
+                        screen.X = scr.Bounds.X;
+                        screen.Y = scr.Bounds.Y;
+                        screen.Width = scr.Bounds.Width;
+                        screen.Height = scr.Bounds.Height;
+                    }
+
+                    i++;
+                }
+
+                if (mouseClick.Y > Screen.PrimaryScreen.Bounds.Height - 35)
+                    locationy = Screen.PrimaryScreen.Bounds.Height - Height - 45;
+                else
+                    locationy = mouseClick.Y - Height - 20;
+                locationx = mouseClick.X - Width / 2;
+
+                Location = new Point(locationx, locationy);
+
+                // If form goes over screen edge
+                if (Left < screen.Left)
+                    Left = screen.Left + 10;
+                if (Top < screen.Top)
+                    Top = screen.Top + 10;
+                if (Right > screen.Right)
+                    Left = screen.Right - Width - 10;
+
+                // If form goes over taskbar
+                if (taskbar.Contains(Left, Top) && taskbar.Contains(Right, Top)) // Top taskbar
+                    Top = screen.Top + 10 + taskbar.Height;
+                if (taskbar.Contains(Left, Top)) // Left taskbar
+                    Left = screen.Left + 10 + taskbar.Width;
+                if (taskbar.Contains(Right, Top)) // Right taskbar
+                    Left = screen.Right - Width - 10 - taskbar.Width;
+            }
+        }
+
+        // Search for active taskbars on screen
+        public static List<Rectangle> FindDockedTaskBars()
+        {
+            var dockedRects = new List<Rectangle>();
+            foreach (var tmpScrn in Screen.AllScreens)
+                if (!tmpScrn.Bounds.Equals(tmpScrn.WorkingArea))
+                {
+                    var rect = new Rectangle();
+
+                    var leftDockedWidth = Math.Abs(Math.Abs(tmpScrn.Bounds.Left) - Math.Abs(tmpScrn.WorkingArea.Left));
+                    var topDockedHeight = Math.Abs(Math.Abs(tmpScrn.Bounds.Top) - Math.Abs(tmpScrn.WorkingArea.Top));
+                    var rightDockedWidth = tmpScrn.Bounds.Width - leftDockedWidth - tmpScrn.WorkingArea.Width;
+                    var bottomDockedHeight = tmpScrn.Bounds.Height - topDockedHeight - tmpScrn.WorkingArea.Height;
+                    if (leftDockedWidth > 0)
+                    {
+                        rect.X = tmpScrn.Bounds.Left;
+                        rect.Y = tmpScrn.Bounds.Top;
+                        rect.Width = leftDockedWidth;
+                        rect.Height = tmpScrn.Bounds.Height;
+                    }
+                    else if (rightDockedWidth > 0)
+                    {
+                        rect.X = tmpScrn.WorkingArea.Right;
+                        rect.Y = tmpScrn.Bounds.Top;
+                        rect.Width = rightDockedWidth;
+                        rect.Height = tmpScrn.Bounds.Height;
+                    }
+                    else if (topDockedHeight > 0)
+                    {
+                        rect.X = tmpScrn.WorkingArea.Left;
+                        rect.Y = tmpScrn.Bounds.Top;
+                        rect.Width = tmpScrn.WorkingArea.Width;
+                        rect.Height = topDockedHeight;
+                    }
+                    else if (bottomDockedHeight > 0)
+                    {
+                        rect.X = tmpScrn.WorkingArea.Left;
+                        rect.Y = tmpScrn.WorkingArea.Bottom;
+                        rect.Width = tmpScrn.WorkingArea.Width;
+                        rect.Height = bottomDockedHeight;
+                    }
+
+                    dockedRects.Add(rect);
+                }
+
+            if (dockedRects.Count == 0)
+            {
+                // Taskbar is set to "Auto-Hide".
+            }
+
+            return dockedRects;
+        }
+
+        //
+        //------------------------------------------------------------------------------------
+        //
+
+        // Loading category and building shortcuts
+        private void LoadCategory()
+        {
+            //System.Diagnostics.Debugger.Launch();
+
+            Width = 0;
+            Height = 45;
+            var x = 0;
+            var y = 0;
+            var width = ThisCategory.Width;
+            var columns = 1;
+
+            // Check if icon caches exist for the category being loaded
+            // If not then rebuild the icon cache
+            if (!Directory.Exists(MainPath.path + @"\config\" + ThisCategory.Name + @"\Icons\"))
+                ThisCategory.CacheIcons();
+
+            foreach (var psc in ThisCategory.ShortcutList)
+            {
+                if (columns > width) // creating new row if there are more psc than max width
+                {
+                    x = 0;
+                    y += 45;
+                    Height += 45;
+                    columns = 1;
+                }
+
+                if (Width < width * 55)
+                    Width += 55;
+
+                // OLD
+                //BuildShortcutPanel(x, y, psc);
+
+                // Building shortcut controls
+                var pscPanel = new ucShortcut
+                {
+                    Psc = psc,
+                    MotherForm = this,
+                    ThisCategory = ThisCategory
+                };
+                pscPanel.Location = new Point(x, y);
+                Controls.Add(pscPanel);
+                ControlList.Add(pscPanel);
+                pscPanel.Show();
+                pscPanel.BringToFront();
+
+                // Reset values
+                x += 55;
+                columns++;
+            }
+
+            Width -= 2; // For some reason the width is 2 pixels larger than the shortcuts. Temporary fix
+        }
+
+        // OLD (Having some issues with the uc build, so keeping the old code below)
+        private void BuildShortcutPanel(int x, int y, ProgramShortcut psc)
+        {
+            shortcutPic = new PictureBox();
+            shortcutPic.BackColor = Color.Transparent;
+            shortcutPic.Location = new Point(25, 15);
+            shortcutPic.Size = new Size(25, 25);
+            shortcutPic.BackgroundImage =
+                ThisCategory.LoadImageCache(psc); // Use the local icon cache for the file specified as the icon image
+            shortcutPic.BackgroundImageLayout = ImageLayout.Stretch;
+            shortcutPic.TabStop = false;
+            shortcutPic.Click += (sender, e) => OpenFile(psc.Arguments, psc.FilePath, psc.WorkingDirectory);
+            shortcutPic.Cursor = Cursors.Hand;
+            shortcutPanel.Controls.Add(shortcutPic);
+            shortcutPic.Show();
+            shortcutPic.BringToFront();
+            shortcutPic.MouseEnter += (sender, e) => shortcutPanel.BackColor = Color.Black;
+            shortcutPic.MouseLeave += (sender, e) => shortcutPanel.BackColor = Color.Transparent;
+        }
+
+        // Click handler for shortcuts
+        public void OpenFile(string arguments, string path, string workingDirec)
+        {
+            // starting program from psc panel click
+            var proc = new ProcessStartInfo
+            {
+                Arguments = arguments,
+                FileName = path,
+                WorkingDirectory = workingDirec
+            };
+
+            /*
+            proc.EnableRaisingEvents = false;
+            proc.StartInfo.FileName = path;
+            */
+
+            try
+            {
+                Process.Start(proc);
+            }
+            catch (Exception ex)
+            {
+                MessageBox.Show(ex.Message);
+            }
+        }
+
+        // Closes application upon deactivation
+        private void frmMain_Deactivate(object sender, EventArgs e)
+        {
+            // closes program if user clicks outside form
+            Close();
+        }
+
+        // Keyboard shortcut handlers
+        private void frmMain_KeyDown(object sender, KeyEventArgs e)
+        {
+            try
+            {
+                switch (e.KeyCode)
+                {
+                    case Keys.D1:
+                        ControlList[0].ucShortcut_MouseEnter(sender, e);
+                        break;
+
+                    case Keys.D2:
+                        ControlList[1].ucShortcut_MouseEnter(sender, e);
+                        break;
+
+                    case Keys.D3:
+                        ControlList[2].ucShortcut_MouseEnter(sender, e);
+                        break;
+
+                    case Keys.D4:
+                        ControlList[3].ucShortcut_MouseEnter(sender, e);
+                        break;
+
+                    case Keys.D5:
+                        ControlList[4].ucShortcut_MouseEnter(sender, e);
+                        break;
+
+                    case Keys.D6:
+                        ControlList[5].ucShortcut_MouseEnter(sender, e);
+                        break;
+
+                    case Keys.D7:
+                        ControlList[6].ucShortcut_MouseEnter(sender, e);
+                        break;
+
+                    case Keys.D8:
+                        ControlList[7].ucShortcut_MouseEnter(sender, e);
+                        break;
+
+                    case Keys.D9:
+                        ControlList[8].ucShortcut_MouseEnter(sender, e);
+                        break;
+
+                    case Keys.D0:
+                        ControlList[9].ucShortcut_MouseEnter(sender, e);
+                        break;
+                }
+            }
+            catch
+            {
+            }
+        }
+
+        private void frmMain_KeyUp(object sender, KeyEventArgs e)
+        {
+            //System.Diagnostics.Debugger.Launch();
+            if (e.Modifiers == Keys.Control && e.KeyCode == Keys.Enter && ThisCategory.allowOpenAll)
+                foreach (var usc in ControlList)
+                    usc.ucShortcut_Click(sender, e);
+
+            try
+            {
+                switch (e.KeyCode)
+                {
+                    case Keys.D1:
+                        ControlList[0].ucShortcut_MouseLeave(sender, e);
+                        ControlList[0].ucShortcut_Click(sender, e);
+                        break;
+
+                    case Keys.D2:
+                        ControlList[1].ucShortcut_MouseLeave(sender, e);
+                        ControlList[1].ucShortcut_Click(sender, e);
+
+                        break;
+
+                    case Keys.D3:
+                        ControlList[2].ucShortcut_MouseLeave(sender, e);
+                        ControlList[2].ucShortcut_Click(sender, e);
+                        break;
+
+                    case Keys.D4:
+                        ControlList[3].ucShortcut_MouseLeave(sender, e);
+                        ControlList[3].ucShortcut_Click(sender, e);
+                        break;
+
+                    case Keys.D5:
+                        ControlList[4].ucShortcut_MouseLeave(sender, e);
+                        ControlList[4].ucShortcut_Click(sender, e);
+                        break;
+
+                    case Keys.D6:
+                        ControlList[5].ucShortcut_MouseLeave(sender, e);
+                        ControlList[5].ucShortcut_Click(sender, e);
+                        break;
+
+                    case Keys.D7:
+                        ControlList[6].ucShortcut_MouseLeave(sender, e);
+                        ControlList[6].ucShortcut_Click(sender, e);
+                        break;
+
+                    case Keys.D8:
+                        ControlList[7].ucShortcut_MouseLeave(sender, e);
+                        ControlList[7].ucShortcut_Click(sender, e);
+                        break;
+
+                    case Keys.D9:
+                        ControlList[8].ucShortcut_MouseLeave(sender, e);
+                        ControlList[8].ucShortcut_Click(sender, e);
+                        break;
 
+                    case Keys.D0:
+                        ControlList[9].ucShortcut_MouseLeave(sender, e);
+                        ControlList[9].ucShortcut_Click(sender, e);
+                        break;
+                }
+            }
+            catch
+            {
+                
+            }
         }
     }
 }

+ 15 - 5
TaskbarGroups/Program.cs

@@ -7,9 +7,12 @@ using System.Runtime.InteropServices;
 using System.Reflection;
 using System.Diagnostics;
 using System.Threading;
-
+using TaskbarGroups.NativeMethods;
 namespace TaskbarGroups
 {
+    /// <summary>
+    /// enter point
+    /// </summary>
     static class Program
     {
 
@@ -27,17 +30,24 @@ namespace TaskbarGroups
         {
             // 只运行一个实例
             Process instance = RunningInstance();
-            if ( instance ==null){
+            if (instance == null)
+            {
                 Application.EnableVisualStyles();
                 Application.SetCompatibleTextRenderingDefault(false);
                 Application.Run(new frmMain());
-            }else
+            }
+            else
             {
-                // todo 已启动则打开form
-                //Application.EnableVisualStyles();
+                SetForegroundWindow(instance.MainWindowHandle);
             }
         }
 
+        private static void SetForegroundWindow(IntPtr mainWindowHandle)
+        {
+            IntPtr h = Kernel32.OpenProcess(0x1F0FFF, false, Process.GetCurrentProcess().Id);
+            
+        }
+
         /// <summary>
         /// 检测是否已经启动了一个Application实例
         /// </summary>

+ 54 - 2
TaskbarGroups/TaskbarGroups.csproj

@@ -12,6 +12,21 @@
     <FileAlignment>512</FileAlignment>
     <AutoGenerateBindingRedirects>true</AutoGenerateBindingRedirects>
     <Deterministic>true</Deterministic>
+    <PublishUrl>publish\</PublishUrl>
+    <Install>true</Install>
+    <InstallFrom>Disk</InstallFrom>
+    <UpdateEnabled>false</UpdateEnabled>
+    <UpdateMode>Foreground</UpdateMode>
+    <UpdateInterval>7</UpdateInterval>
+    <UpdateIntervalUnits>Days</UpdateIntervalUnits>
+    <UpdatePeriodically>false</UpdatePeriodically>
+    <UpdateRequired>false</UpdateRequired>
+    <MapFileExtensions>true</MapFileExtensions>
+    <ApplicationRevision>0</ApplicationRevision>
+    <ApplicationVersion>1.0.0.%2a</ApplicationVersion>
+    <IsWebBootstrapper>false</IsWebBootstrapper>
+    <UseApplicationTrust>false</UseApplicationTrust>
+    <BootstrapperEnabled>true</BootstrapperEnabled>
   </PropertyGroup>
   <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
     <PlatformTarget>AnyCPU</PlatformTarget>
@@ -33,8 +48,18 @@
     <WarningLevel>4</WarningLevel>
   </PropertyGroup>
   <ItemGroup>
+    <Reference Include="CustomMarshalers" />
+    <Reference Include="Microsoft.WindowsAPICodePack, Version=1.1.5.0, Culture=neutral, PublicKeyToken=8985beaab7ea3f04, processorArchitecture=MSIL">
+      <HintPath>..\packages\Microsoft-WindowsAPICodePack-Core.1.1.5\lib\net472\Microsoft.WindowsAPICodePack.dll</HintPath>
+    </Reference>
+    <Reference Include="Microsoft.WindowsAPICodePack.Shell, Version=1.1.5.0, Culture=neutral, PublicKeyToken=8985beaab7ea3f04, processorArchitecture=MSIL">
+      <HintPath>..\packages\Microsoft-WindowsAPICodePack-Shell.1.1.5\lib\net472\Microsoft.WindowsAPICodePack.Shell.dll</HintPath>
+    </Reference>
+    <Reference Include="PresentationCore" />
+    <Reference Include="PresentationFramework" />
     <Reference Include="System" />
     <Reference Include="System.Core" />
+    <Reference Include="System.Xaml" />
     <Reference Include="System.Xml.Linq" />
     <Reference Include="System.Data.DataSetExtensions" />
     <Reference Include="Microsoft.CSharp" />
@@ -44,8 +69,15 @@
     <Reference Include="System.Net.Http" />
     <Reference Include="System.Windows.Forms" />
     <Reference Include="System.Xml" />
+    <Reference Include="WindowsBase" />
+    <Reference Include="WindowsFormsIntegration" />
   </ItemGroup>
   <ItemGroup>
+    <Compile Include="Models\BaseModel.cs" />
+    <Compile Include="Models\Category.cs" />
+    <Compile Include="NativeMethods\Kernel32.cs" />
+    <Compile Include="NativeMethods\Shell32.cs" />
+    <Compile Include="NativeMethods\User32.cs" />
     <Compile Include="Pages\frmMain.cs">
       <SubType>Form</SubType>
     </Compile>
@@ -60,6 +92,12 @@
     <Compile Include="Views\BaseForm.cs">
       <SubType>Form</SubType>
     </Compile>
+    <Compile Include="Views\ucShortcut.cs">
+      <SubType>UserControl</SubType>
+    </Compile>
+    <Compile Include="Views\ucShortcut.Designer.cs">
+      <DependentUpon>ucShortcut.cs</DependentUpon>
+    </Compile>
     <EmbeddedResource Include="Pages\frmMain.resx">
       <DependentUpon>frmMain.cs</DependentUpon>
     </EmbeddedResource>
@@ -72,6 +110,10 @@
       <AutoGen>True</AutoGen>
       <DependentUpon>Resources.resx</DependentUpon>
     </Compile>
+    <EmbeddedResource Include="Views\ucShortcut.resx">
+      <DependentUpon>ucShortcut.cs</DependentUpon>
+    </EmbeddedResource>
+    <None Include="packages.config" />
     <None Include="Properties\Settings.settings">
       <Generator>SettingsSingleFileGenerator</Generator>
       <LastGenOutput>Settings.Designer.cs</LastGenOutput>
@@ -86,9 +128,19 @@
     <None Include="App.config" />
   </ItemGroup>
   <ItemGroup>
-    <Folder Include="Models\" />
-    <Folder Include="NativeMethods\" />
     <Folder Include="Utils\" />
   </ItemGroup>
+  <ItemGroup>
+    <BootstrapperPackage Include=".NETFramework,Version=v4.7.2">
+      <Visible>False</Visible>
+      <ProductName>Microsoft .NET Framework 4.7.2 %28x86 and x64%29</ProductName>
+      <Install>true</Install>
+    </BootstrapperPackage>
+    <BootstrapperPackage Include="Microsoft.Net.Framework.3.5.SP1">
+      <Visible>False</Visible>
+      <ProductName>.NET Framework 3.5 SP1</ProductName>
+      <Install>false</Install>
+    </BootstrapperPackage>
+  </ItemGroup>
   <Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
 </Project>

+ 47 - 0
TaskbarGroups/Views/ucShortcut.Designer.cs

@@ -0,0 +1,47 @@
+
+namespace TaskbarGroups.Views
+{
+    partial class ucShortcut
+    {
+        /// <summary> 
+        /// Required designer variable.
+        /// </summary>
+        private System.ComponentModel.IContainer components = null;
+
+        /// <summary> 
+        /// Clean up any resources being used.
+        /// </summary>
+        /// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
+        protected override void Dispose(bool disposing)
+        {
+            if (disposing && (components != null))
+            {
+                components.Dispose();
+            }
+            base.Dispose(disposing);
+        }
+
+        #region Component Designer generated code
+
+        /// <summary> 
+        /// Required method for Designer support - do not modify 
+        /// the contents of this method with the code editor.
+        /// </summary>
+        private void InitializeComponent()
+        {
+            this.SuspendLayout();
+            // 
+            // ucShortcut
+            // 
+            this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 12F);
+            this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
+            this.Name = "ucShortcut";
+            this.Size = new System.Drawing.Size(715, 330);
+            this.Load += new System.EventHandler(this.ucShortcut_Load);
+            this.ResumeLayout(false);
+
+        }
+
+        #endregion
+    }
+}

+ 35 - 0
TaskbarGroups/Views/ucShortcut.cs

@@ -0,0 +1,35 @@
+using System;
+using System.Collections.Generic;
+using System.ComponentModel;
+using System.Data;
+using System.Drawing;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+using System.Windows.Forms;
+
+namespace TaskbarGroups.Views
+{
+    /// <summary>
+    /// 
+    /// </summary>
+    public partial class ucShortcut : UserControl
+    {
+        public ProgramShortcut Psc { get; set; }
+        public frmMain MotherForm { get; set; }
+        public bool ThisCategory { get; set; }
+
+        public ucShortcut()
+        {
+            InitializeComponent();
+        }
+
+        private void ucShortcut_Load(object sender, EventArgs e)
+        {
+            Show();
+        }
+
+
+
+    }
+}

+ 120 - 0
TaskbarGroups/Views/ucShortcut.resx

@@ -0,0 +1,120 @@
+<?xml version="1.0" encoding="utf-8"?>
+<root>
+  <!-- 
+    Microsoft ResX Schema 
+    
+    Version 2.0
+    
+    The primary goals of this format is to allow a simple XML format 
+    that is mostly human readable. The generation and parsing of the 
+    various data types are done through the TypeConverter classes 
+    associated with the data types.
+    
+    Example:
+    
+    ... ado.net/XML headers & schema ...
+    <resheader name="resmimetype">text/microsoft-resx</resheader>
+    <resheader name="version">2.0</resheader>
+    <resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
+    <resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
+    <data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
+    <data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
+    <data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
+        <value>[base64 mime encoded serialized .NET Framework object]</value>
+    </data>
+    <data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
+        <value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
+        <comment>This is a comment</comment>
+    </data>
+                
+    There are any number of "resheader" rows that contain simple 
+    name/value pairs.
+    
+    Each data row contains a name, and value. The row also contains a 
+    type or mimetype. Type corresponds to a .NET class that support 
+    text/value conversion through the TypeConverter architecture. 
+    Classes that don't support this are serialized and stored with the 
+    mimetype set.
+    
+    The mimetype is used for serialized objects, and tells the 
+    ResXResourceReader how to depersist the object. This is currently not 
+    extensible. For a given mimetype the value must be set accordingly:
+    
+    Note - application/x-microsoft.net.object.binary.base64 is the format 
+    that the ResXResourceWriter will generate, however the reader can 
+    read any of the formats listed below.
+    
+    mimetype: application/x-microsoft.net.object.binary.base64
+    value   : The object must be serialized with 
+            : System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
+            : and then encoded with base64 encoding.
+    
+    mimetype: application/x-microsoft.net.object.soap.base64
+    value   : The object must be serialized with 
+            : System.Runtime.Serialization.Formatters.Soap.SoapFormatter
+            : and then encoded with base64 encoding.
+
+    mimetype: application/x-microsoft.net.object.bytearray.base64
+    value   : The object must be serialized into a byte array 
+            : using a System.ComponentModel.TypeConverter
+            : and then encoded with base64 encoding.
+    -->
+  <xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
+    <xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
+    <xsd:element name="root" msdata:IsDataSet="true">
+      <xsd:complexType>
+        <xsd:choice maxOccurs="unbounded">
+          <xsd:element name="metadata">
+            <xsd:complexType>
+              <xsd:sequence>
+                <xsd:element name="value" type="xsd:string" minOccurs="0" />
+              </xsd:sequence>
+              <xsd:attribute name="name" use="required" type="xsd:string" />
+              <xsd:attribute name="type" type="xsd:string" />
+              <xsd:attribute name="mimetype" type="xsd:string" />
+              <xsd:attribute ref="xml:space" />
+            </xsd:complexType>
+          </xsd:element>
+          <xsd:element name="assembly">
+            <xsd:complexType>
+              <xsd:attribute name="alias" type="xsd:string" />
+              <xsd:attribute name="name" type="xsd:string" />
+            </xsd:complexType>
+          </xsd:element>
+          <xsd:element name="data">
+            <xsd:complexType>
+              <xsd:sequence>
+                <xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
+                <xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
+              </xsd:sequence>
+              <xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
+              <xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
+              <xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
+              <xsd:attribute ref="xml:space" />
+            </xsd:complexType>
+          </xsd:element>
+          <xsd:element name="resheader">
+            <xsd:complexType>
+              <xsd:sequence>
+                <xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
+              </xsd:sequence>
+              <xsd:attribute name="name" type="xsd:string" use="required" />
+            </xsd:complexType>
+          </xsd:element>
+        </xsd:choice>
+      </xsd:complexType>
+    </xsd:element>
+  </xsd:schema>
+  <resheader name="resmimetype">
+    <value>text/microsoft-resx</value>
+  </resheader>
+  <resheader name="version">
+    <value>2.0</value>
+  </resheader>
+  <resheader name="reader">
+    <value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
+  </resheader>
+  <resheader name="writer">
+    <value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
+  </resheader>
+</root>

+ 5 - 0
TaskbarGroups/packages.config

@@ -0,0 +1,5 @@
+<?xml version="1.0" encoding="utf-8"?>
+<packages>
+  <package id="Microsoft-WindowsAPICodePack-Core" version="1.1.5" targetFramework="net472" />
+  <package id="Microsoft-WindowsAPICodePack-Shell" version="1.1.5" targetFramework="net472" />
+</packages>