Example #1
0
 public Section(MonitorLayout _layout, RECT _rect)
 {
     layout = _layout;
     rect   = _rect;
 }
Example #2
0
        // Methods
        public fts_winsnap()
        {
            // Set working dir to exe dir so app don't crash on startup
            var  exePath     = System.IO.Path.GetDirectoryName(Application.ExecutablePath);
            bool autoStarted = Environment.CurrentDirectory != exePath;

            if (autoStarted)
            {
                Environment.CurrentDirectory = exePath;
            }

            // Read settings from disk (if there are any)
            LoadSettings();

            // Check registry for startup option
            var registryKey = Microsoft.Win32.Registry.CurrentUser.OpenSubKey("SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Run", true);
            var v           = registryKey.GetValue("fts_winsnap") as string;

            if (v == Application.ExecutablePath)
            {
                _runOnStartup = true;
            }

            // WinForm Component initialization
            InitializeComponent();
            this._notifyIcon.ContextMenu = new System.Windows.Forms.ContextMenu(new System.Windows.Forms.MenuItem[] {
                new System.Windows.Forms.MenuItem("Show fts_winsnap", (object sender, System.EventArgs e) => { this?.Show(); }),
                new System.Windows.Forms.MenuItem("Close fts_winsnap", (object sender, System.EventArgs e) => { this?.Close(); })
            });
            Application.ApplicationExit += new EventHandler(this.OnApplicationExit);

            // Minimize to task bar if app was automatically launched by Windows on startup
            if (autoStarted)
            {
                this.ShowInTaskbar = false;
                this.WindowState   = FormWindowState.Minimized;
            }

            // Register hotkeys
            RegisterHotKey(this.Handle, 0, Constants.WM_MOD_CTRL | Constants.WM_MOD_ALT, (int)Keys.Left);
            RegisterHotKey(this.Handle, 1, Constants.WM_MOD_CTRL | Constants.WM_MOD_ALT, (int)Keys.Right);
            RegisterHotKey(this.Handle, 2, Constants.WM_MOD_CTRL | Constants.WM_MOD_ALT, (int)Keys.Up);
            RegisterHotKey(this.Handle, 3, Constants.WM_MOD_CTRL | Constants.WM_MOD_ALT, (int)Keys.Down);
            RegisterHotKey(this.Handle, 4, Constants.WM_MOD_CTRL | Constants.WM_MOD_SHIFT | Constants.WM_MOD_ALT, (int)Keys.Down);
            RegisterHotKey(this.Handle, 5, Constants.WM_MOD_CTRL | Constants.WM_MOD_SHIFT | Constants.WM_MOD_ALT, (int)Keys.Left);
            RegisterHotKey(this.Handle, 6, Constants.WM_MOD_CTRL | Constants.WM_MOD_SHIFT | Constants.WM_MOD_ALT, (int)Keys.Right);
            RegisterHotKey(this.Handle, 7, Constants.WM_MOD_CTRL | Constants.WM_MOD_SHIFT | Constants.WM_MOD_ALT, (int)Keys.Up);


            // Initialize fonts for UI
            var helveticaFamily = new FontFamily("Helvetica");
            var monospaceFamily = new FontFamily(System.Drawing.Text.GenericFontFamilies.Monospace);

            var pfc = new System.Drawing.Text.PrivateFontCollection();

            pfc.AddFontFile(@"Karla-Regular.ttf");
            var karlaFamily = pfc.Families[0];


            // Initialize per-monitor settings
            while (_settings.monitorSettings.Count < Screen.AllScreens.Count())
            {
                var newSettings = new Settings.MonitorSettings();
                _settings.monitorSettings.Add(newSettings);
            }

            // createLabel helper
            Func <string, FontFamily, float, FontStyle, Padding, Rectangle, Label> createLabel =
                (string text, FontFamily fontFamily, float fontScale, FontStyle fontStyle, Padding padding, Rectangle bounds) => {
                var newLabel = new Label();
                newLabel.Text     = text;
                newLabel.Font     = new Font(fontFamily, newLabel.Font.Size * fontScale, fontStyle);
                newLabel.AutoSize = true;
                newLabel.Padding  = padding;
                newLabel.Bounds   = bounds;
                this.Controls.Add(newLabel);
                return(newLabel);
            };

            // Create UI for each monitor
            int idx = 1;
            int y   = 0;

            foreach (var monitor in Screen.AllScreens)
            {
                // Create a new layout for this monitor
                var newLayout = new MonitorLayout(monitor);
                _layouts.Add(newLayout);

                // Grab settings for this monitor
                var monitorSettings = _settings.monitorSettings[idx - 1];

                // Monitor #
                var titleLabel = createLabel("Monitor " + idx.ToString(), karlaFamily, 2f, FontStyle.Bold, new Padding(4), new Rectangle(0, y, 0, 0));

                // Resolution: 1920x1080
                var resolutionLabel = createLabel("Resolution: " + monitor.Bounds.Width.ToString() + "x" + monitor.Bounds.Height.ToString(),
                                                  karlaFamily, 1.5f, FontStyle.Regular, new Padding(32, 3, 3, 3), new Rectangle(titleLabel.Bounds.Left, titleLabel.Bounds.Bottom, 0, 0));

                // Resize: <NumberField>
                var resizeLabel = createLabel("Resize: ", karlaFamily, 1.5f, FontStyle.Regular, new Padding(32, 0, 0, 0), new Rectangle(0, resolutionLabel.Bottom, 0, 0));

                var resizeControl = new NumericUpDown();
                resizeControl.Bounds        = new Rectangle(resizeLabel.Bounds.Right + 4, resizeLabel.Bounds.Top, 50, 0);
                resizeControl.Minimum       = -30;
                resizeControl.Maximum       = 30;
                resizeControl.Value         = monitorSettings.adjustSize;
                resizeControl.AutoSize      = true;
                resizeControl.TabStop       = false;
                resizeControl.ValueChanged += (object sender, EventArgs e) => {
                    // Update settings
                    newLayout.adjustSize       = (int)resizeControl.Value;
                    monitorSettings.adjustSize = newLayout.adjustSize;
                    SaveSettings();
                };

                this.Controls.Add(resizeControl);


                // Layout plus predefined buttons
                var layout = createLabel("Layout: ", karlaFamily, 1.5f, FontStyle.Regular, new Padding(32, 8, 3, 3), new Rectangle(resizeLabel.Bounds.Left, resizeLabel.Bounds.Bottom + 5, 0, 0));

                var    customField = new System.Windows.Forms.TextBox();
                Button selectedBtn = null;
                Button customBtn   = null;

                // Helper to style button visuals
                Action <Button> styleButton = (Button b) => {
                    b.Padding   = new Padding(3);
                    b.AutoSize  = true;
                    b.Font      = new Font(helveticaFamily, b.Font.Size * 1.2f, FontStyle.Bold);
                    b.FlatStyle = FlatStyle.Flat;
                    b.FlatAppearance.BorderSize         = 1;
                    b.FlatAppearance.BorderColor        = midGray;
                    b.FlatAppearance.MouseOverBackColor = medBlue;
                    b.FlatAppearance.MouseDownBackColor = medBlue;
                    b.FlatAppearance.CheckedBackColor   = darkBlue;
                    b.ForeColor = darkGray;
                    b.BackColor = faintGray;
                };

                // Helper to set layous from json (throw exception on bad json!)
                Action <string> UpdateLayouts = (string json) => {
                    var layoutEntries         = JsonConvert.DeserializeObject <IList <IList <int> > >(json);
                    List <Rectangle> newRects = new List <Rectangle>(layoutEntries.Count);
                    foreach (var layoutEntry in layoutEntries)
                    {
                        int minX = layoutEntry[0];
                        int minY = layoutEntry[1];
                        int maxX = layoutEntry[2];
                        int maxY = layoutEntry[3];
                        newRects.Add(new Rectangle(minX, minY, maxX - minX, maxY - minY));
                    }
                    newLayout.SetLayouts(newRects);
                };

                // Handler for when user clicks button
                Action <Button, string> clickButton = (Button b, string json) => {
                    // Update layouts
                    try { UpdateLayouts(json); }
                    catch (System.Exception /*ex*/) { return; }

                    // Show/Hide json field if 'Custom' button is clicked
                    if (b == customBtn)
                    {
                        customField.Show();
                    }
                    else
                    {
                        customField.Hide();
                    }

                    // Reset colors on previously selected button
                    if (selectedBtn != null)
                    {
                        selectedBtn.ForeColor = darkGray;
                        selectedBtn.BackColor = faintGray;
                    }

                    // Set colors on nwely selected button
                    b.BackColor = darkBlue;
                    b.ForeColor = Color.White;
                    selectedBtn = b;

                    // Update settings
                    monitorSettings.selectedButton = b.Text;
                    SaveSettings();
                };

                Button initialButton = null;
                string initialJson   = null;

                // Helper to make a button
                Func <Rectangle, string, string, Button> makeButton = (Rectangle bounds, string label, string json) => {
                    // Create button
                    var newBtn = new System.Windows.Forms.Button();
                    newBtn.Bounds = bounds;
                    newBtn.Text   = label;
                    styleButton(newBtn);

                    Action <object, EventArgs> onClick = (object s, EventArgs e) => { clickButton(newBtn, json); };
                    newBtn.Click += (object s, EventArgs e) => { onClick(s, e); };

                    this.Controls.Add(newBtn);

                    // Check if this is the default selection
                    if (label == monitorSettings.selectedButton)
                    {
                        initialButton = newBtn;
                        initialJson   = json;
                    }

                    return(newBtn);
                };

                Button btn = null;
                int    pad = 3;

                btn = makeButton(new Rectangle(layout.Bounds.Right, layout.Bounds.Top, 0, 0), "1x1", "[[0,0,100,100]]");

                btn = makeButton(new Rectangle(btn.Bounds.Right + pad, btn.Bounds.Top, 0, 0), "2x1", "[[0,0,50,100], [50,0,100,100]]");
                btn = makeButton(new Rectangle(btn.Bounds.Right + pad, btn.Bounds.Top, 0, 0), "1x2", "[[0,0,100,50], [0,50,100,100]]");
                btn = makeButton(new Rectangle(btn.Bounds.Right + pad, btn.Bounds.Top, 0, 0), "2x2", "[[0,0,50,50], [50,0,100,50], [0,50,50,100], [50,50,100,100]]");

                btn = makeButton(new Rectangle(layout.Bounds.Right, btn.Bounds.Bottom + 5, 0, 0), "3x1", "[[0,0,33,100], [33,0,67,100], [67,0,100,100]]");
                btn = makeButton(new Rectangle(btn.Bounds.Right + pad, btn.Bounds.Top, 0, 0), "1x3", "[[0,0,100,33], [0,33,100,67], [0,67,100,100]]");
                btn = makeButton(new Rectangle(btn.Bounds.Right + pad, btn.Bounds.Top, 0, 0), "3x3", "[[0,0,33,33], [33,0,67,33], [67,0,100,33], [0,33,33,67], [33,33,67,67], [67,33,100,67], [0,67,33,100], [33,67,67,100], [67,67,100,100]]");

                customBtn = makeButton(new Rectangle(btn.Bounds.Right + pad, btn.Bounds.Top, 0, 0), "Custom", monitorSettings.customJson);


                // Custom field holds JSON layout data. Can be hand edited by user if 'Custom' button is selected
                customField.Bounds       = new Rectangle(layout.Bounds.Right, btn.Bounds.Bottom + 4, this.Width / 2, layout.Bounds.Height);
                customField.TabStop      = false;
                customField.Font         = new Font(monospaceFamily, customField.Font.Size, FontStyle.Regular);
                customField.Text         = monitorSettings.customJson;
                customField.TextChanged += (object sender, EventArgs e) => {
                    try {
                        UpdateLayouts(customField.Text);
                        customField.BackColor = Color.White;

                        monitorSettings.customJson = customField.Text;
                        SaveSettings();
                    }
                    catch (Exception /*ex*/) {
                        customField.BackColor = paleRed;
                    }
                };
                this.Controls.Add(customField);

                // Click initial button for initial state
                clickButton(initialButton, initialJson);

                y = customField.Bounds.Bottom + 15;
                ++idx;
            }


            // 'Controls' section header
            var controls = createLabel("Controls", karlaFamily, 2f, FontStyle.Bold, new Padding(4), new Rectangle(0, y, 0, 0));

            // 'Move: Ctrl  +  Alt +  ArrowKey'
            var moveLabel    = createLabel("Move: ", karlaFamily, 1.5f, FontStyle.Regular, new Padding(32, 3, 3, 3), new Rectangle(controls.Bounds.Left, controls.Bounds.Bottom, 0, 0));
            var moveControls = createLabel("Ctrl  +  Alt +  ArrowKey", karlaFamily, 1.5f, FontStyle.Regular, new Padding(3), new Rectangle(110, moveLabel.Bounds.Top, 0, 0));

            // 'Expand: Ctrl  +  Alt  +  Shift  +  ArrowKey'
            var expandLabel = createLabel("Expand: ", karlaFamily, 1.5f, FontStyle.Regular, new Padding(32, 3, 3, 3), new Rectangle(moveLabel.Bounds.Left, moveLabel.Bounds.Bottom, 0, 0));
            var expandText  = createLabel("Ctrl  +  Alt  +  Shift  +  ArrowKey", karlaFamily, 1.5f, FontStyle.Regular, new Padding(3), new Rectangle(110, expandLabel.Bounds.Top, 0, 0));


            // 'Options' section header
            var optionsLabel = createLabel("Options", karlaFamily, 2f, FontStyle.Bold, new Padding(4), new Rectangle(0, expandText.Bounds.Bottom + 30, 0, 0));

            var runOnStartupLabel = createLabel("Run on Startup: ", karlaFamily, 1.5f, FontStyle.Regular, new Padding(32, 0, 0, 0), new Rectangle(0, optionsLabel.Bottom, 0, 0));

            var runOnStartup = new System.Windows.Forms.CheckBox();

            runOnStartup.Checked         = _runOnStartup;
            runOnStartup.Bounds          = new Rectangle(runOnStartupLabel.Bounds.Right + 10, runOnStartupLabel.Bounds.Top + 5, 0, 0);
            runOnStartup.AutoSize        = true;
            runOnStartup.CheckedChanged += (object sender, EventArgs e) => {
                // Add or remove register key
                var rk = Microsoft.Win32.Registry.CurrentUser.OpenSubKey("SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Run", true);

                if (runOnStartup.Checked)
                {
                    rk.SetValue("fts_winsnap", Application.ExecutablePath);
                }
                else
                {
                    rk.DeleteValue("fts_winsnap", false);
                }

                // Update settings
                _runOnStartup = runOnStartup.Checked;
                SaveSettings();
            };
            this.Controls.Add(runOnStartup);
        }