using System;
using System.Drawing;
using System.IO;
using System.Windows.Forms;

namespace trxGui
{
    public partial class Form1 : Form
    {
        int window_width = 800;
        int window_height = 480;
        int spec_height = 88;
        int wf_height = 70;
        int button_size = 32;
        Font bigfnt;
        int lastsendtone = 0;
        bool old_hwptt = false;
        bool pttkey_pressed = false;
        static public UdpQueue valq = new UdpQueue();

        String screensafertime = "";

        public Form1()
        {
            InitializeComponent();

            try
            {
                String s = statics.RunExternalProgram("gsettings", "get org.gnome.desktop.session idle-delay");
                screensafertime = s.Substring(7);
                Console.WriteLine("disable screen saver. Time was:"+screensafertime);
                statics.RunExternalProgram("gsettings", "set org.gnome.desktop.session idle-delay 0");
            }
            catch
            {
                screensafertime = "";
            }

            load_Setup();

            panel_bigwf.MouseWheel += panel_bigwf_MouseWheel;
            panel_bigspec.MouseWheel += panel_bigwf_MouseWheel;

            panel_smallwf.MouseWheel += panel_smallwf_MouseWheel;
            panel_smallspec.MouseWheel += panel_smallwf_MouseWheel;

            // set the position of the GUI elements for various screen resolutions
            scaleElements();

            // center in screen, this makes it easy to use or adapt to screen sizes
            CenterToScreen();

            // test OS type
            OperatingSystem osversion = System.Environment.OSVersion;
            if (osversion.VersionString.Contains("indow"))
                statics.ostype = 0; // Win$
            else
                statics.ostype = 1; // Linux

            // if this program was started from another loacation
            // set the working directory to the path of the .exe file
            // so it can find trxdriver
            try
            {
                String s = System.Reflection.Assembly.GetExecutingAssembly().Location;
                s = Path.GetDirectoryName(s);
                Directory.SetCurrentDirectory(s);
                Console.WriteLine("working path: " + s);
            }
            catch (Exception e)
            {
                Console.WriteLine("cannot set working path: " + e.ToString());
            }

            Udp.InitUdp();

            statics.StartQO100trx();

            timer_draw.Start();

            sendAndRefreshRXTXoffset();
        }

        // buttons left side, vertical row
        int but_left_leftmargin = 5;
        int but_left_topmargin = 4;
        int but_left_width = 24;
        int but_left_heigth = 36;
        int but_left_spacing = 4;

        void scaleElements()
        {
            int wsize = 0;
            if (statics.windowsize == wsize++)
            {
                // sizes for screens 1920x1080 pixel
                window_width = 1920;
                window_height = 1080;
                button_size = 64;
                bigfnt = new Font("Verdana", 24.0f);
            }

            if (statics.windowsize == wsize++)
            {
                // sizes for screens 1600x1050 pixel
                window_width = 1600;
                window_height = 1050;
                button_size = 64;
                bigfnt = new Font("Verdana", 24.0f);
            }

            if (statics.windowsize == wsize++)
            {
                // sizes for screens 1200x720 pixel
                window_width = 1155;
                window_height = 720;
                button_size = 48;
                bigfnt = new Font("Verdana", 24.0f);
            }

            if (statics.windowsize == wsize++)
            {
                // sizes for screens 1200x480 pixel
                window_width = 1155;
                window_height = 480;
                button_size = 32;
                bigfnt = new Font("Verdana", 24.0f);
            }

            if (statics.windowsize == wsize++)
            {
                // sizes for screens 1024x768 pixel
                window_width = 1024;
                window_height = 768;
                button_size = 40;
                bigfnt = new Font("Verdana", 24.0f);
            }

            if (statics.windowsize == wsize++)
            {
                // sizes for screens 1024x600 pixel
                window_width = 1024;
                window_height = 600;
                button_size = 32;
                bigfnt = new Font("Verdana", 24.0f);
            }

            if (statics.windowsize == wsize++)
            {
                // sizes for screens 800x600 pixel
                window_width = 800;
                window_height = 600;
                button_size = 32;
                bigfnt = new Font("Verdana", 14.0f);
            }

            if (statics.windowsize == wsize++)
            {
                // sizes for screens 800x480 pixel
                window_width = 800;
                window_height = 480;
                button_size = 32;
                bigfnt = new Font("Verdana", 14.0f);
            }

            if (statics.windowsize == wsize++)
            {
                // sizes for screens 640x480 pixel
                window_width = 640;
                window_height = 480;
                button_size = 32;
                bigfnt = new Font("Verdana", 14.0f);
            }

            if (statics.windowsize == wsize++)
            {
                // sizes for screens 480x320 pixel
                window_width = 480;
                window_height = 320;
                button_size = 20;
                bigfnt = new Font("Verdana", 12.0f);
            }

            // size of complete window
            this.Width = window_width;
            this.Height = window_height;

            panel_screen.Location = new Point(but_left_leftmargin, but_left_topmargin+40);
            panel_screen.Width = but_left_width;
            panel_screen.Height = but_left_heigth;

            panel_sync.Location = new Point(but_left_leftmargin, panel_screen.Location.Y + panel_screen.Height + but_left_spacing);
            panel_sync.Width = but_left_width;
            panel_sync.Height = but_left_heigth;

            panel_beaconlock.Location = new Point(but_left_leftmargin, panel_sync.Location.Y + panel_sync.Height + but_left_spacing);
            panel_beaconlock.Width = but_left_width;
            panel_beaconlock.Height = but_left_heigth;

            panel_save.Location = new Point(but_left_leftmargin, panel_beaconlock.Location.Y + panel_beaconlock.Height + but_left_spacing);
            panel_save.Width = but_left_width;
            panel_save.Height = but_left_heigth;

            panel_recall.Location = new Point(but_left_leftmargin, panel_save.Location.Y + panel_save.Height + but_left_spacing);
            panel_recall.Width = but_left_width;
            panel_recall.Height = but_left_heigth;

            panel_testtone.Location = new Point(but_left_leftmargin, panel_recall.Location.Y + panel_recall.Height + but_left_spacing);
            panel_testtone.Width = but_left_width;
            panel_testtone.Height = but_left_heigth;


            // main panels
            int left = panel_screen.Location.X + panel_screen.Width + 4;
            int panel_width = window_width - 15 - left;
            int diagspacey = RectangleToScreen(ClientRectangle).Height - but_left_topmargin - 5 - 40 - 16 - 15 - 16 - 4 - button_size - 5;
            spec_height = diagspacey / 4;
            wf_height = diagspacey / 4; 

            panel_qrg.Location = new Point(left, but_left_topmargin);
            panel_qrg.Width = panel_width;
            panel_qrg.Height = 40; 


            panel_bigspec.Width = panel_width;
            panel_bigspec.Height = spec_height;

            panel_switchbandplan.Width = 16;
            panel_switchbandplan.Height = 16;

            panel_bandplan.Width = panel_width - panel_switchbandplan.Width;
            panel_bandplan.Height = 16;

            panel_bigwf.Width = panel_width;
            panel_bigwf.Height = wf_height;

            panel_rxline.Width = panel_width;
            panel_rxline.Height = 15;

            panel_smallspec.Width = panel_width;
            panel_smallspec.Height = spec_height;

            panel_smallqrg.Width = panel_width;
            panel_smallqrg.Height = 16;

            panel_smallwf.Width = panel_width;
            panel_smallwf.Height = wf_height;


            panel_bigspec.Location = new Point(left, panel_qrg.Location.Y + panel_qrg.Height + 5);
            panel_bandplan.Location = new Point(left, panel_bigspec.Location.Y + panel_bigspec.Height);
            panel_switchbandplan.Location = new Point(panel_bandplan.Location.X + panel_bandplan.Width, panel_bigspec.Location.Y + panel_bigspec.Height);
            panel_bigwf.Location = new Point(left, panel_bandplan.Location.Y + panel_bandplan.Height);

            panel_rxline.Location = new Point(left, panel_bigwf.Location.Y + panel_bigwf.Height);

            panel_smallspec.Location = new Point(left, panel_rxline.Location.Y + panel_rxline.Height);
            panel_smallqrg.Location = new Point(left, panel_smallspec.Location.Y + panel_smallspec.Height);
            panel_smallwf.Location = new Point(left, panel_smallqrg.Location.Y + panel_smallqrg.Height);

            // bottom buttons
            int xspace = 4;

            panel_pavucontrol.Size = panel_rxfilter.Size = panel_txfilter.Size = panel_rfloop.Size = panel_audioloop.Size = panel_comp.Size = panel_setup.Size = panel_info.Size = panel_rit.Size = panel_xit.Size = panel_copyRtoT.Size = panel_copyTtoR.Size = panel_agc.Size = panel_txmute.Size = new Size(button_size, button_size);
            panel_rit.Location = new Point(left, panel_smallwf.Location.Y + panel_smallwf.Height + 4);
            panel_xit.Location = new Point(panel_rit.Location.X + panel_rit.Width + xspace, panel_rit.Location.Y);

            panel_copyRtoT.Location = new Point(panel_xit.Location.X + panel_xit.Width + xspace + 6, panel_rit.Location.Y);
            panel_copyTtoR.Location = new Point(panel_copyRtoT.Location.X + panel_copyRtoT.Width + xspace, panel_rit.Location.Y);

            panel_agc.Location = new Point(panel_copyTtoR.Location.X + panel_copyTtoR.Width + xspace + 6, panel_rit.Location.Y);
            panel_txmute.Location = new Point(panel_agc.Location.X + panel_agc.Width + xspace, panel_rit.Location.Y);
            panel_comp.Location = new Point(panel_txmute.Location.X + panel_txmute.Width + xspace, panel_rit.Location.Y);

            panel_rxfilter.Location = new Point(panel_comp.Location.X + panel_comp.Width + xspace + 6, panel_rit.Location.Y);
            panel_txfilter.Location = new Point(panel_rxfilter.Location.X + panel_rxfilter.Width + xspace, panel_rit.Location.Y);

            panel_audioloop.Location = new Point(panel_txfilter.Location.X + panel_txfilter.Width + xspace + 6, panel_rit.Location.Y);
            panel_rfloop.Location = new Point(panel_audioloop.Location.X + panel_audioloop.Width + xspace, panel_rit.Location.Y);

            panel_info.Location = new Point(panel_bigspec.Location.X + panel_bigspec.Width - panel_info.Width, panel_rit.Location.Y);
            panel_setup.Location = new Point(panel_info.Location.X - panel_setup.Width - 5, panel_rit.Location.Y);
            panel_pavucontrol.Location = new Point(panel_setup.Location.X - panel_pavucontrol.Width - 5, panel_rit.Location.Y);

            // PTT Panel
            panel1.Location = new Point(panel_rfloop.Location.X + panel_rfloop.Width + xspace + 6, panel_rit.Location.Y);
            panel1.Size = new Size(panel_pavucontrol.Location.X - panel1.Location.X - 6, panel_rfloop.Height);

            statics.panel_bigspec_Width = panel_bigspec.Width;
            statics.panel_bigspec_Height = panel_bigspec.Height;
            statics.panel_bigwf_Width = panel_bigwf.Width;
            statics.panel_bigwf_Height = panel_bigwf.Height;
            statics.panel_smallspec_Width = panel_smallspec.Width;
            statics.panel_smallspec_Height = panel_smallspec.Height;
            statics.panel_smallwf_Width = panel_smallwf.Width;
            statics.panel_smallwf_Height = panel_smallwf.Height;
        }

        DateTime dts = DateTime.UtcNow;
        private void panel_bigspec_Paint(object sender, PaintEventArgs e)
        {
            Bitmap bm = Udp.getBigSpecBitmap();

            if (bm != null)
            {
                e.Graphics.DrawImage(bm, 0, 0);
                bm.Dispose();
            }
        }

        bool pttstat = false;

        private void timer_draw_Tick(object sender, EventArgs e)
        {
            timer_draw.Stop();

            if (Udp.getBigSpecBitmap_avail())
            {
                panel_bigspec.Invalidate();
            }

            if (Udp.getSmallSpecBitmap_avail())
            {
                panel_smallspec.Invalidate();
            }

            if (Udp.getBigWFBitmap_avail())
            {
                panel_bigwf.Invalidate();
            }

            if (Udp.getSmallWFBitmap_avail())
            {
                panel_smallwf.Invalidate();
            }

            if (statics.pttmode == 0)
            {
                // PTT on/off
                if (Control.ModifierKeys == Keys.Shift && pttstat == false)
                {
                    // PTT pressed (shift key)
                    statics.ptt = !statics.ptt;
                    panel1.Invalidate();
                    setPTT(statics.ptt);
                    pttstat = true;
                }
                if (Control.ModifierKeys == Keys.None)
                {
                    pttstat = false;
                }
            }
            if (statics.pttmode == 1)
            {
                // Push to Talk
                if (Control.ModifierKeys == Keys.Shift && !statics.ptt)
                {
                    // PTT pressed (shift key)
                    statics.ptt = true;
                    pttkey_pressed = true;
                    panel1.Invalidate();
                    setPTT(statics.ptt);
                }
                if (Control.ModifierKeys == Keys.None && statics.ptt && pttkey_pressed)
                {
                    // PTT released (shift key)
                    statics.ptt = false;
                    pttkey_pressed = false;
                    panel1.Invalidate();
                    setPTT(statics.ptt);
                }
            }

            // change color of PTT button if ptt state changed in the driver
            if(statics.hwptt != old_hwptt)
            {
                old_hwptt = statics.hwptt;
                statics.ptt = statics.hwptt;
                panel1.Invalidate();
            }

            if (statics.GotAudioDevices == 1)
            {
                // this is called once just after the trxdriver has started
                // do all init jobs here which needs a running trxdriver

                // just got the list of audio devices
                statics.GotAudioDevices = 0;

                // check if the current selected device is in the new device list
                bool pbfound = false;
                foreach(String s in statics.AudioPBdevs)
                {
                    if(s == statics.AudioPBdev)
                    {
                        pbfound = true;
                        break;
                    }
                }

                bool capfound = false;
                foreach (String s in statics.AudioCAPdevs)
                {
                    if (s == statics.AudioCAPdev)
                    {
                        capfound = true;
                        break;
                    }
                }

                if(!pbfound)
                {
                    Console.WriteLine("NO Playback Device found, using default");
                    if (statics.AudioPBdevs.Length == 0)
                        statics.AudioPBdev = "Default";
                    else
                        statics.AudioPBdev = statics.AudioPBdevs[0];
                }

                if (!capfound)
                {
                    Console.WriteLine("NO Captur Device found, using default");
                    if (statics.AudioCAPdevs.Length == 0)
                        statics.AudioCAPdev = "Default";
                    else
                        statics.AudioCAPdev = statics.AudioCAPdevs[0];
                }

                statics.newaudiodevs = true;
                sendAudioDevs();
                statics.sendBaseQRG();
                sendPlutoAddress();
                panel_comp_Click(null, null);   // send "compress"
                panel_agc_Click(null, null);   // send "AGC"
                panel_txmute_Click(null, null);
                panel_rxfilter_Click(null, null);
                panel_txfilter_Click(null, null);
                statics.sendReferenceOffset(statics.rfoffset);
                sendCpuSpeed();
                sendTXpower();
                sendPTTmode();
                this.Text += " GUI: " + formatSN(statics.gui_serno) + " Driver: " + formatSN(statics.driver_serno);
                // check consistency
                if(statics.gui_serno != statics.driver_serno)
                {
                    MessageBox.Show("Warning!\nGUI and Driver have different serial numbers. Please re-install this software", "Version Number Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
                }
                // check for updates
                try
                {
                    using (StreamReader sr = new StreamReader("version.txt"))
                    {
                        int actver = ReadInt(sr);
                        Console.WriteLine("act version:" + actver);
                        if(actver > statics.gui_serno)
                        {
                            //MessageBox.Show("a new Version is avialable at Github:" + actver.ToString(), "NEW VERSION", MessageBoxButtons.OK, MessageBoxIcon.Information);
                            String nv = " (new:V" + ((double)actver / 100).ToString() + ")";
                            this.Text += nv.Replace(',', '.');
                        }
                    }
                    File.Delete("version.txt");
                }
                catch { }

                panel_beaconlock.Invalidate();
            }

            if(statics.beaconoffset != oldbcnoffset)
            {
                oldbcnoffset = statics.beaconoffset;
                panel_qrg.Invalidate();
            }

            int rsteps = Udp.GetRotary();
            if(rsteps != 0)
            {
                int b = Math.Abs(rsteps);

                int factor = 10000;
                if (b == 1) factor = 25;
                else if (b == 2) factor = 50;
                else if (b == 3) factor = 100;
                else if (b == 4) factor = 250;
                else if (b == 5) factor = 500;
                else if (b == 6) factor = 1000;

                if (rsteps > 0) factor = -factor;

                if (statics.rit)
                    statics.RXoffset += factor;

                if (statics.xit)
                    statics.TXoffset += factor;

                if (statics.rit || statics.xit)
                    sendAndRefreshRXTXoffset();
            }

            if (statics.corrfact != 0)
            {
                if (statics.corractive > 0)
                {
                    if (statics.autosync)
                    {
                        Console.WriteLine("correct by corrfact: " + statics.corrfact);
                        statics.RXoffset -= statics.corrfact;
                        statics.TXoffset -= statics.corrfact;
                        sendAndRefreshRXTXoffset();
                    }
                    statics.corractive--;
                }
                statics.corrfact = 0;
            }

            if(lastsendtone != statics.sendtone)
            {
                panel_testtone.Invalidate();
                lastsendtone = statics.sendtone;
            }

            if(valq.Count() > 0)
            {
                Byte[] tarr = valq.Getarr();
                Udp.UdpSendData(tarr);
            }

            timer_draw.Start();
        }

        private String formatSN(int sn)
        {
            String s = "V";

            s += (sn / 100).ToString();
            s += ".";
            s += (sn - (sn / 100) * 100).ToString();

            return s;
        }

        int oldbcnoffset = -1;

        private void Form1_FormClosing(object sender, FormClosingEventArgs e)
        {
            statics.StartQO100trx(false);
            save_Setup();
            if (screensafertime.Length > 0)
            {
                try
                {
                    Console.WriteLine("restore screen saver time:" + screensafertime);
                    statics.RunExternalProgram("gsettings", "set org.gnome.desktop.session idle-delay " + screensafertime);
                }
                catch {}
            }
            statics.running = false;
        }

        private void panel_smallspec_Paint(object sender, PaintEventArgs e)
        {
            Bitmap bm = Udp.getSmallSpecBitmap();

            if (bm != null)
            {
                e.Graphics.DrawImage(bm, 0, 0);
                bm.Dispose();
            }
        }

        private void panel_bigwf_Paint(object sender, PaintEventArgs e)
        {
            Bitmap bm = Udp.getBigWFBitmap();

            if (bm != null)
            {
                e.Graphics.DrawImage(bm, 0, 0);
                bm.Dispose();
            }
        }

        private void panel_smallwf_Paint(object sender, PaintEventArgs e)
        {
            Bitmap bm = Udp.getSmallWFBitmap();

            if (bm != null)
            {
                e.Graphics.DrawImage(bm, 0, 0);
                bm.Dispose();
            }
        }

        private void panel_bigwf_MouseClick(object sender, MouseEventArgs e)
        {
            tuneBig(e);
            statics.corractive = statics.corractiveanz;
        }

        private void panel_smallwf_MouseClick(object sender, MouseEventArgs e)
        {
            tuneSmall(e);
        }

        private void tuneBig(MouseEventArgs e)
        {
            int x = e.X;
            x = x * 1120 / panel_bigspec.Width;

            // left mouse button or touch panel click
            if (e.Button == MouseButtons.Left)
            {
                if (statics.calmode == 0)
                {
                    // normal operation
                    // if both, RX and TX, is selected, keep offset between RX and TX
                    if (statics.rit && statics.xit)
                    {
                        statics.RXTXoffset = statics.RXoffset - statics.TXoffset;
                        statics.RXoffset = x * 500;
                        statics.TXoffset = x * 500 - statics.RXTXoffset;
                    }
                    else if (statics.rit)
                        statics.RXoffset = x * 500;
                    else if (statics.xit)
                        statics.TXoffset = x * 500;

                    statics.RXTXoffset = statics.RXoffset - statics.TXoffset;

                    sendAndRefreshRXTXoffset();
                }
                else if (statics.calmode == 1)
                {
                    // cal to BPSK beacon
                    int off = x * 500 - 280000;
                    //Console.WriteLine("Pluto offset: " + off + " Hz");
                    if(off > 0)
                        statics.calfreq += (UInt32)off;
                    else if (off < 0)
                        statics.calfreq -= (UInt32)(-off);

                    statics.sendBaseQRG(statics.calfreq);
                }
                else if (statics.calmode == 2)
                {
                    int off = x * 500 - 280000;
                    //Console.WriteLine("offset: " + off);
                    statics.lnboffset += off;
                    statics.sendBaseQRG();
                }
            }

            if (e.Button == MouseButtons.Right)
            {
                statics.RXoffset = x * 500;
                statics.TXoffset = x * 500;
                sendAndRefreshRXTXoffset();
            }
        }

        private void sendAndRefreshRXTXoffset()
        {
            statics.sendRXTXoffset();

            panel_qrg.Invalidate();
            panel_rxline.Invalidate();
        }

        private void tuneSmall(MouseEventArgs e)
        {
            // small WF: 25Hz per pixel, with the tune qrg in the middle
            int x = e.X;
            x = x * 1120 / panel_smallwf.Width;
            int hz = (x - 560) * 25;
            

            if (e.Button == MouseButtons.Left)
            {
                if (statics.calmode == 0)
                {
                    if(statics.rit)
                        statics.RXoffset += hz;
                    if (statics.xit)
                        statics.TXoffset += hz;
                    sendAndRefreshRXTXoffset();
                }
                else if (statics.calmode == 1)
                {
                    //Console.WriteLine("Pluto offset: " + hz);
                    if (hz > 0)
                        statics.calfreq += (UInt32)hz;
                    else if (hz < 0)
                        statics.calfreq -= (UInt32)(-hz);

                    statics.sendBaseQRG(statics.calfreq);
                    //Console.WriteLine("calfreq: " + statics.calfreq);
                }
                else if (statics.calmode == 2)
                {
                    Console.WriteLine("offset: " + hz);
                    statics.lnboffset += hz;
                    statics.sendBaseQRG();
                }
            }

            if (e.Button == MouseButtons.Right)
            {
                statics.RXoffset += hz;
                statics.TXoffset += hz;
                sendAndRefreshRXTXoffset();
            }
        }

        private void panel_bigwf_MouseWheel(object sender, MouseEventArgs e)
        {
            int factor = 100;
            if (Control.ModifierKeys == Keys.Alt) factor = 1000;
            if (Control.ModifierKeys == Keys.Control) factor = 10000;

            if (statics.rit)
            {
                if (e.Delta > 0) //wheel direction
                    statics.RXoffset += factor;
                else
                    statics.RXoffset -= factor;

            }
            if (statics.xit)
            {
                if (e.Delta > 0) //wheel direction
                    statics.TXoffset += factor;
                else
                    statics.TXoffset -= factor;
            }

            if (statics.rit || statics.xit)
                sendAndRefreshRXTXoffset();
        }

        private void panel_smallwf_MouseWheel(object sender, MouseEventArgs e)
        {
            if (statics.rit)
            {
                if (e.Delta > 0) //wheel direction
                    statics.RXoffset += 10;
                else
                    statics.RXoffset -= 10;
            }

            if (statics.xit)
            {
                if (e.Delta > 0) //wheel direction
                    statics.TXoffset += 10;
                else
                    statics.TXoffset -= 10;
            }

            if (statics.rit || statics.xit)
                sendAndRefreshRXTXoffset();
        }

        private void panel_bigwf_MouseHover(object sender, EventArgs e)
        {
            panel_bigwf.Focus();
        }

        private void panel_bigwf_MouseMove(object sender, MouseEventArgs e)
        {
            panel_bigwf.Focus();
            int x = e.X * 1120 / panel_bigspec.Width;
            statics.rxmouse = x * 500;
            panel_qrg.Invalidate();
        }

        private void panel_bigspec_MouseLeave(object sender, EventArgs e)
        {
            statics.rxmouse = -1;
            panel_qrg.Invalidate();
        }

        private void panel_bigspec_MouseMove(object sender, MouseEventArgs e)
        {
            panel_bigspec.Focus();
            int x = e.X * 1120 / panel_bigspec.Width;
            statics.rxmouse = x * 500;
            panel_qrg.Invalidate();
        }

        private void panel_smallspec_MouseLeave(object sender, EventArgs e)
        {
            statics.rxmouse = -1;
            panel_qrg.Invalidate();
        }

        private void panel_smallspec_MouseMove(object sender, MouseEventArgs e)
        {
            panel_smallspec.Focus();
            int x = e.X * 1120 / panel_bigspec.Width;
            int hz = (x - 560) * 25;
            statics.rxmouse = statics.RXoffset + hz;
            panel_qrg.Invalidate();
        }

        private void panel_smallwf_MouseLeave(object sender, EventArgs e)
        {
            statics.rxmouse = -1;
            panel_qrg.Invalidate();
        }

        private void panel_smallwf_MouseMove(object sender, MouseEventArgs e)
        {
            panel_smallwf.Focus();
            int x = e.X * 1120 / panel_bigspec.Width;
            int hz = (x - 560) * 25;
            statics.rxmouse = statics.RXoffset + hz;
            panel_qrg.Invalidate();
        }

        private void panel_bigwf_MouseLeave(object sender, EventArgs e)
        {
            statics.rxmouse = -1;
            panel_qrg.Invalidate();
        }

        private void panel_bigspec_MouseHover(object sender, EventArgs e)
        {
            panel_bigspec.Focus();
        }

        private void panel_smallspec_MouseHover(object sender, EventArgs e)
        {
            panel_smallspec.Focus();
        }

        private void panel_smallwf_MouseHover(object sender, EventArgs e)
        {
            panel_smallwf.Focus();
        }

        Font smallfnt = new Font("Verdana", 8.0f);
        private void panel_smallqrg_Paint(object sender, PaintEventArgs e)
        {
            using(Graphics gr = e.Graphics)
            {
                String s = "0 Hz";
                int x = panel_smallqrg.Width / 2 - 10;
                gr.DrawString(s, smallfnt, Brushes.Black, x, 0);
                for(int i=120; i<500; i+=120)
                {
                    s = (i * 25 / 1000).ToString() + "kHz";
                    x = i * panel_smallqrg.Width / 1120 + panel_smallqrg.Width / 2 - 10;
                    gr.DrawString(s, smallfnt, Brushes.Black, x, 0);
                }
                for (int i = -120; i > -500; i -= 120)
                {
                    s = (i * 25 / 1000).ToString() + "kHz";
                    x = i * panel_smallqrg.Width / 1120 + panel_smallqrg.Width / 2 - 10;
                    gr.DrawString(s, smallfnt, Brushes.Black, x, 0);
                }
            }
        }

        int qrgToPixelpos(int qrg)
        {
            qrg -= 10489000;   // rest is kHz
            qrg -= 470;
            qrg *= 2;
            qrg = qrg * panel_bigspec.Width / 1120;
            return qrg;
        }

        private void panel_bandplan_Paint(object sender, PaintEventArgs e)
        {
            Font qrgfnt = new Font("Verdana", 9.0f);
            Font bpfnt;
            if (panel_bigspec.Width > 1000)
                bpfnt = new Font("Verdana", 9.0f);
            else
                bpfnt = new Font("Verdana", 8.0f);

            Bandplan bp = new Bandplan();
            using (Graphics gr = e.Graphics)
            {
                if (statics.bandplan_mode == 0)
                {
                    gr.FillRectangle(new SolidBrush(Color.DarkBlue), 0, 0, panel_bandplan.Width, panel_bandplan.Height);
                    if(panel_bigspec.Width > 1000)
                        gr.DrawString("Bandplan", bpfnt, Brushes.White, 0, -1);
                    for (int i = 0; i < bp.be.Length - 1; i++)
                    {
                        int x = qrgToPixelpos(bp.be[i].from);
                        int w = qrgToPixelpos(bp.be[i + 1].from) - x;
                        Color col = bp.be[i].col;
                        gr.FillRectangle(new SolidBrush(col), x, 0, w, panel_bandplan.Height);
                        String s = bp.be[i].text;
                        int spos = qrgToPixelpos(bp.be[i].textpos);
                        gr.DrawString(s, bpfnt, Brushes.White, spos, -1);
                    }
                }
                else if (statics.bandplan_mode == 1)
                {
                    // QO100 RX qrgs
                    gr.FillRectangle(new SolidBrush(Color.DarkBlue), 0, 0, panel_bandplan.Width, panel_bandplan.Height);
                    if (panel_bigspec.Width > 1000)
                        gr.DrawString("RX", qrgfnt, Brushes.White, 0, -1);
                    for (int qrg = 10489500; qrg <= 10490000; qrg += 50)
                    {
                        int spos = qrgToPixelpos(qrg);
                        if (qrg > 10489500)
                        {
                            String sqrg = (qrg - 10489000).ToString();
                            gr.DrawString(sqrg, qrgfnt, Brushes.White, spos - 12, 0);
                        }
                        else
                        {
                            String sqrg = String.Format("{0:0.000}", (double)qrg / 1000.0);
                            gr.DrawString(sqrg, qrgfnt, Brushes.White, spos - 30, 0);
                        }
                    }
                }
                else if (statics.bandplan_mode == 2)
                {
                    // QO100 TX qrgs
                    gr.FillRectangle(new SolidBrush(Color.DarkBlue), 0, 0, panel_bandplan.Width, panel_bandplan.Height);
                    if (panel_bigspec.Width > 1000)
                        gr.DrawString("TX", qrgfnt, Brushes.White, 0, -1);
                    for (int qrg = 10489500; qrg <= 10490000; qrg += 50)
                    {
                        int spos = qrgToPixelpos(qrg);
                        if (qrg > 10489500)
                        {
                            String sqrg = (qrg - 2400000- 8089500).ToString();
                            gr.DrawString(sqrg, qrgfnt, Brushes.White, spos - 12, 0);
                        }
                        else
                        {
                            String sqrg = String.Format("{0:0.000}", (qrg - 8089500) / 1000.0);
                            gr.DrawString(sqrg, qrgfnt, Brushes.White, spos - 30, 0);
                        }
                    }
                }
                else if (statics.bandplan_mode == 3)
                {
                    // Pluto RX qrgs
                    gr.FillRectangle(new SolidBrush(Color.DarkBlue), 0, 0, panel_bandplan.Width, panel_bandplan.Height);
                    if (panel_bigspec.Width > 1000)
                        gr.DrawString("RX", qrgfnt, Brushes.White, 0, -1);
                    for (int qrg = (int)statics.rxqrg - 250000; qrg <= (int)statics.rxqrg + 250000; qrg += 50000)
                    {
                        int spos = qrgToPixelpos(qrg/1000 + 10489000 - (qrg/1000000)*1000);
                        if (qrg > ((int)statics.rxqrg - 250000))
                        {
                            String sqrg = ((qrg - (((int)statics.rxqrg) / 1000000) * 1000000)/1000).ToString();
                            gr.DrawString(sqrg, qrgfnt, Brushes.White, spos - 12, 0);
                        }
                        else
                        {
                            String sqrg = String.Format("{0:0.000}", (double)qrg / 1000000.0);
                            gr.DrawString(sqrg, qrgfnt, Brushes.White, spos - 30, 0);
                        }
                    }
                }
                else if (statics.bandplan_mode == 4)
                {
                    // Pluto TX qrgs
                    gr.FillRectangle(new SolidBrush(Color.DarkBlue), 0, 0, panel_bandplan.Width, panel_bandplan.Height);
                    if (panel_bigspec.Width > 1000)
                        gr.DrawString("TX", qrgfnt, Brushes.White, 0, -1);
                    for (Int64 qrg = (Int64)statics.txqrg - 250000; qrg <= (Int64)statics.txqrg + 250000; qrg += 50000)
                    {
                        int spos = qrgToPixelpos((int)(qrg / 1000 + 10489500 - (qrg / 1000000) * 1000));
                        if (qrg > ((Int64)statics.txqrg - 250000))
                        {
                            String sqrg = ((qrg - (((Int64)statics.txqrg) / 1000000) * 1000000) / 1000).ToString();
                            gr.DrawString(sqrg, qrgfnt, Brushes.White, spos - 12, 0);
                        }
                        else
                        {
                            String sqrg = String.Format("{0:0.000}", (double)qrg / 1000000.0);
                            gr.DrawString(sqrg, qrgfnt, Brushes.White, spos - 30, 0);
                        }
                    }
                }
            }
        }

       
        Font smlfnt = new Font("Verdana", 10.0f);
        int titrightpos = 10;
        int mouserightpos = 790;
        int bigy = 2;

        // insert a space betwenn each char:
        // string.Join(" ", s.ToCharArray())
        Brush brushrx = new SolidBrush(Color.FromArgb(0, 230, 100));
        Brush brushtx = new SolidBrush(Color.FromArgb(160, 0, 0));
        private void panel_qrg_Paint(object sender, PaintEventArgs e)
        {
            using (Graphics gr = e.Graphics)
            {
                if (panel_bigspec.Width > 900)
                {
                    int mrp = mouserightpos;
                    if (panel_bigspec.Width > 1300)
                        mrp = 1300;

                    double val = (double)(statics.RXoffset + 10489470000) / 1e6;
                    String s = String.Format("RX:" + "{0:0.000000}" + " MHz", val);
                    gr.DrawString(s, bigfnt, brushrx, titrightpos, bigy);

                    val = (double)(statics.TXoffset + 10489470000) / 1e6 - 8089.5;
                    s = String.Format("TX:" + "{0:0.000000}" + " MHz", val);
                    gr.DrawString(s, bigfnt, brushtx, 420 + titrightpos, bigy);

                    if (statics.rxmouse != -1)
                    {
                        val = (double)(statics.rxmouse + 10489470000) / 1e6;
                        s = String.Format(language.GetText("Mouse:") + "  {0:0.000000}", val);
                        gr.DrawString(s, smlfnt, Brushes.Blue, mrp + titrightpos, 0);
                    }
                    else
                    {
                        gr.FillRectangle(Brushes.Gray, mrp + titrightpos, 0, panel_qrg.Width - (mrp + titrightpos), panel_qrg.Height);
                    }

                    s = String.Format("Drift : {0:0}" + " Hz", statics.beaconoffset);
                    if (statics.beaconlock) s += " (corr)";
                    gr.DrawString(s, smlfnt, Brushes.Blue, mrp + titrightpos, 20);
                }
                else
                {
                    double val = (double)(statics.RXoffset + 10489470000) / 1e6;
                    String s = String.Format("RX:" + "{0:0.000000}" + " MHz", val);
                    gr.DrawString(s, bigfnt, Brushes.Green, titrightpos, bigy-5);

                    val = (double)(statics.TXoffset + 10489470000) / 1e6 - 8089.5;
                    s = String.Format("TX:" + "{0:0.000000}" + " MHz", val);
                    gr.DrawString(s, bigfnt, Brushes.DarkRed, titrightpos, bigy+16);

                    int mrp = 420;
                    if (panel_bigspec.Width < 700) mrp = 390;
                    if (panel_bigspec.Width < 500) mrp = 250;

                    if (statics.rxmouse != -1)
                    {
                        val = (double)(statics.rxmouse + 10489470000) / 1e6;
                        s = String.Format(language.GetText("Mouse:") + "  {0:0.000000}", val);
                        gr.DrawString(s, smlfnt, Brushes.Blue, mrp + titrightpos, 0);
                    }
                    else
                    {
                        gr.FillRectangle(Brushes.Gray, mrp + titrightpos, 0, panel_qrg.Width - (mrp + titrightpos), panel_qrg.Height);
                    }

                    s = String.Format("Drift : {0:0}" + " Hz", statics.beaconoffset);
                    if (statics.beaconlock) s += " (corr)";
                    gr.DrawString(s, smlfnt, Brushes.Blue, mrp + titrightpos, 20);
                }
            }
        }

        private void setPTT(bool onoff)
        {
            Byte[] txb = new Byte[2];
            txb[0] = 4;
            txb[1] = (Byte)(onoff ? 1 : 0);
            Udp.UdpSendData(txb);
        }

        private void panel1_Paint(object sender, PaintEventArgs e)
        {
            using (Graphics gr = e.Graphics)
            {
                if (statics.ptt)
                {
                    gr.FillRectangle(Brushes.Red, 0, 0, panel1.Width, panel1.Height);
                    using (Bitmap bm = new Bitmap(Properties.Resources.ptt_tx))
                        drawBitmap(gr, bm, panel1.Width / 2 - bm.Width / 2, 0,button_size*2);
                }
                else
                {
                    gr.FillRectangle(Brushes.Green, 0, 0, panel1.Width, panel1.Height);
                    using (Bitmap bm = new Bitmap(Properties.Resources.ptt_rx))
                        drawBitmap(gr, bm, panel1.Width / 2 - bm.Width / 2, 0, button_size * 2);
                }
            }
        }

        private void panel1_MouseClick(object sender, MouseEventArgs e)
        {
            if (statics.pttmode == 0)
            {
                if (statics.ptt) statics.ptt = false;
                else statics.ptt = true;
                setPTT(statics.ptt);
                panel1.Invalidate();
            }
        }

        private void panel1_MouseDown(object sender, MouseEventArgs e)
        {
            if (statics.pttmode == 1 && !statics.ptt)
            {
                statics.ptt = true;
                setPTT(statics.ptt);
                panel1.Invalidate();
            }
        }

        private void panel1_MouseUp(object sender, MouseEventArgs e)
        {
            if (statics.pttmode == 1 && statics.ptt)
            {
                statics.ptt = false;
                setPTT(statics.ptt);
                panel1.Invalidate();
            }
        }

        private void butto_setup_click(object sender, EventArgs e)
        {
            int oldpluto = statics.plutousb;
            String oldpladr = statics.plutoaddress;

            Form_setup setupForm = new Form_setup();

            // Show the settings form
            var res = setupForm.ShowDialog();
            if(res == DialogResult.OK)
            {
                sendAudioDevs();
                statics.sendBaseQRG();
                statics.sendReferenceOffset(statics.rfoffset);
                sendCpuSpeed();
                sendTXpower();
                sendPTTmode();

                save_Setup();

                if (oldpluto != statics.plutousb || oldpladr != statics.plutoaddress)
                {
                    // pluto setting has been changed, restart required
                    MessageBox.Show("Pluto settings changed. Press OK to close this software, then start it again", "RESTART REQUIRED", MessageBoxButtons.OK, MessageBoxIcon.Warning);
                    Close();
                }
            }
        }

        private void sendAudioDevs()
        {
            try
            {
                if (!statics.newaudiodevs) return;
                statics.newaudiodevs = false;

                //Console.WriteLine("<" + statics.AudioPBdev.Trim() + ">" + "<" + statics.AudioCAPdev + ">");
                Byte[] pb = statics.StringToByteArrayUtf8(statics.AudioPBdev.Trim());
                Byte[] cap = statics.StringToByteArrayUtf8(statics.AudioCAPdev.Trim());

                if (pb.Length > 100 || cap.Length > 100) return;

                Byte[] txb = new Byte[201];
                for (int i = 0; i < txb.Length; i++) txb[i] = 0;
                Array.Copy(pb, 0, txb, 1, pb.Length);
                Array.Copy(cap, 0, txb, 101, cap.Length);
                txb[0] = 7;
                Udp.UdpSendData(txb);
            }
            catch
            {
                // no audio devs
            }
        }
              

        private String ReadString(StreamReader sr)
        {
            try
            {
                String s = sr.ReadLine();
                if (s != null)
                {
                    return s;
                }
            }
            catch { }
            return " ";
        }

        private int ReadInt(StreamReader sr)
        {
            int v;

            try
            {
                String s = sr.ReadLine();
                if (s != null)
                {
                    v = Convert.ToInt32(s);
                    return v;
                }
            }
            catch { }
            return 0;
        }

        private UInt32 ReadUInt32(StreamReader sr)
        {
            UInt32 v;

            try
            {
                String s = sr.ReadLine();
                if (s != null)
                {
                    v = Convert.ToUInt32(s);
                    return v;
                }
            }
            catch { }
            return 0;
        }

        private double ReadMyDouble(StreamReader sr)
        {
            double v;

            try
            {
                String s = sr.ReadLine();
                if (s != null)
                {
                    v = statics.MyToDouble(s);
                    return v;
                }
            }
            catch { }
            return 0;
        }

        void load_Setup()
        {
            try
            {
                String fn = statics.getHomePath("", "trx.cfg");
                using (StreamReader sr = new StreamReader(fn))
                {
                    statics.AudioPBdev = ReadString(sr);
                    statics.AudioCAPdev = ReadString(sr);
                    statics.RXTXoffset = ReadInt(sr); statics.TXoffset -= statics.RXTXoffset;
                    String dummy3 = ReadString(sr);
                    statics.plutousb = ReadInt(sr);
                    statics.plutoaddress = ReadString(sr);
                    String dummy1 = ReadString(sr);
                    bool dummy2 = ReadString(sr) == "1";
                    statics.compressor = ReadString(sr) == "1";
                    statics.rxfilter = ReadInt(sr);
                    statics.txfilter = ReadInt(sr);
                    statics.rxmute = ReadString(sr) == "1";
                    statics.rit = ReadString(sr) == "1";
                    statics.xit = ReadString(sr) == "1";
                    String dummy4 = ReadString(sr);
                    statics.beaconlock = ReadString(sr) == "1";
                    statics.rxqrg = ReadUInt32(sr);
                    statics.txqrg = ReadUInt32(sr);
                    statics.rfoffset = ReadInt(sr);
                    statics.lnboffset = ReadInt(sr);
                    statics.cpuspeed = ReadInt(sr);
                    statics.bandplan_mode = ReadInt(sr);
                    statics.language = ReadInt(sr);
                    statics.palette = ReadInt(sr);
                    statics.audioHighpass = ReadString(sr) == "1";
                    statics.txpower = ReadInt(sr);
                    statics.windowsize = ReadInt(sr);
                    statics.autosync = ReadString(sr) == "1";
                    statics.pttmode = ReadInt(sr);
                    statics.micboost = ReadInt(sr);
                }
            }
            catch
            {
            }
        }

        void save_Setup()
        {
            try
            {
                using (StreamWriter sw = new StreamWriter(statics.getHomePath("", "trx.cfg")))
                {
                    sw.WriteLine(statics.AudioPBdev);
                    sw.WriteLine(statics.AudioCAPdev);
                    sw.WriteLine(statics.RXTXoffset.ToString());
                    sw.WriteLine("");
                    sw.WriteLine(statics.plutousb.ToString());
                    sw.WriteLine(statics.plutoaddress);
                    sw.WriteLine("");
                    sw.WriteLine("");
                    sw.WriteLine(statics.compressor ? "1" : "0");
                    sw.WriteLine(statics.rxfilter.ToString());
                    sw.WriteLine(statics.txfilter.ToString());
                    sw.WriteLine(statics.rxmute ? "1" : "0");
                    sw.WriteLine(statics.rit ? "1" : "0");
                    sw.WriteLine(statics.xit ? "1" : "0");
                    sw.WriteLine("");
                    sw.WriteLine(statics.beaconlock ? "1" : "0");
                    sw.WriteLine(statics.rxqrg.ToString());
                    sw.WriteLine(statics.txqrg.ToString());
                    sw.WriteLine(statics.rfoffset.ToString());
                    sw.WriteLine(statics.lnboffset.ToString());
                    sw.WriteLine(statics.cpuspeed.ToString());
                    sw.WriteLine(statics.bandplan_mode.ToString());
                    sw.WriteLine(statics.language.ToString());
                    sw.WriteLine(statics.palette.ToString());
                    sw.WriteLine(statics.audioHighpass ? "1" : "0");
                    sw.WriteLine(statics.txpower.ToString());
                    sw.WriteLine(statics.windowsize.ToString());
                    sw.WriteLine(statics.autosync ? "1" : "0");
                    sw.WriteLine(statics.pttmode.ToString());
                    sw.WriteLine(statics.micboost.ToString());
                }
            }
            catch { }
        }

        private void bt_info_click(object sender, EventArgs e)
        {
            Form_info fi = new Form_info();

            // Show the settings form
            var res = fi.ShowDialog();
            if (res == DialogResult.OK)
            {
            }
        }

        private void sendPlutoAddress()
        {
            //Console.WriteLine("send pluto ID <" + statics.plutoaddress.Trim() + ">");
            Byte[] iparr = statics.StringToByteArrayUtf8(statics.plutoaddress.Trim());

            Byte[] txb = new Byte[iparr.Length + 2];
            txb[0] = 10;
            txb[1] = (Byte)statics.plutousb;
            Array.Copy(iparr, 0, txb, 2, iparr.Length);
            Udp.UdpSendData(txb);
        }

        private void panel_rit_Click(object sender, EventArgs e)
        {
            statics.rit = !statics.rit;
            panel_rit.Invalidate();
        }

        private void panel_xit_Click(object sender, EventArgs e)
        {
            statics.xit = !statics.xit;
            panel_xit.Invalidate();
        }

        private void drawBitmap(Graphics gr, Bitmap bm, int x=0, int y=0, int sizex=0)
        {
            Bitmap bm_resized;
            if (sizex != 0)
                bm_resized = new Bitmap(bm, sizex, button_size);
            else
                bm_resized = new Bitmap(bm, button_size, button_size);

            gr.DrawImage(bm_resized, x, y);
        }

        private void drawButtonPanel(Graphics gr, bool state, Bitmap bm, Bitmap bminact)
        {
            if (state)
                drawBitmap(gr, bm);
            else
                drawBitmap(gr, bminact);
        }

        private void panel_rit_Paint(object sender, PaintEventArgs e)
        {
            using (Bitmap bm = new Bitmap(Properties.Resources.rxqrg))
                using (Bitmap bminact = new Bitmap(Properties.Resources.rxqrg_inact))
                    drawButtonPanel(e.Graphics, statics.rit, bm, bminact);
        }

        private void panel_xit_Paint(object sender, PaintEventArgs e)
        {
            using (Bitmap bm = new Bitmap(Properties.Resources.txqrg))
                using (Bitmap bminact = new Bitmap(Properties.Resources.txqrg_inact))
                    drawButtonPanel(e.Graphics, statics.xit, bm, bminact);
        }

        
        private void panel_copyRtoT_Paint(object sender, PaintEventArgs e)
        {
            using (Bitmap bm = new Bitmap(Properties.Resources.rt_button))
                using (Bitmap bminact = new Bitmap(Properties.Resources.rt_button_inact))
                    drawButtonPanel(e.Graphics,true, bm, bminact);
        }

        private void panel_copyTtoR_Paint(object sender, PaintEventArgs e)
        {
            using (Bitmap bm = new Bitmap(Properties.Resources.tr_button))
                using (Bitmap bminact = new Bitmap(Properties.Resources.tr_button_inact))
                    drawButtonPanel(e.Graphics, true, bm, bminact);
        }

        private void panel_copyRtoT_Click(object sender, EventArgs e)
        {
            statics.TXoffset = statics.RXoffset;
            statics.RXTXoffset = 0;
            sendAndRefreshRXTXoffset();
            panel_copyRtoT.Invalidate();
        }

        private void panel_agc_Paint(object sender, PaintEventArgs e)
        {
            using (Bitmap bm = new Bitmap(Properties.Resources.txaudio_button))
                drawButtonPanel(e.Graphics, true, bm, null);
        }

        private void panel_txmute_Paint(object sender, PaintEventArgs e)
        {
            using (Bitmap bm = new Bitmap(Properties.Resources.mute))
                using (Bitmap bminact = new Bitmap(Properties.Resources.mute_inact))
                    drawButtonPanel(e.Graphics, statics.rxmute, bm, bminact);
        }

        void sendCpuSpeed()
        {
            Byte[] txb = new Byte[2];
            txb[0] = 17;
            txb[1] = (Byte)statics.cpuspeed;
            Udp.UdpSendData(txb);
        }

        void sendPTTmode()
        {
            Byte[] txb = new Byte[2];
            txb[0] = 23;
            txb[1] = (Byte)statics.pttmode;
            Udp.UdpSendData(txb);
        }

        void sendTXpower()
        {
            Byte[] txb = new Byte[2];
            txb[0] = 19;
            txb[1] = (Byte)Math.Abs(statics.txpower); // send positive value
            Udp.UdpSendData(txb);
        }

        private void panel_agc_Click(object sender, EventArgs e)
        {
            if (e != null)
            {
                // check if alraey open
                foreach (Form frm in Application.OpenForms)
                    if (frm.Name == "Form2_agc") return;

                Form2_agc frmagc = new Form2_agc(Location,valq);
                frmagc.Show();
            }
            else
            {
                // init after program start
                Byte[] txb = new Byte[3];
                txb[0] = 11;
                txb[1] = (Byte)(statics.audioHighpass ? 1 : 0);
                txb[2] = (Byte)statics.micboost;
                Udp.UdpSendData(txb);
            }
        }

        private void panel_txmute_Click(object sender, EventArgs e)
        {
            if (e != null) statics.rxmute = !statics.rxmute;
            Byte[] txb = new Byte[2];
            txb[0] = 14;
            txb[1] = (Byte)(statics.rxmute ? 1 : 0);
            Udp.UdpSendData(txb);
            panel_txmute.Invalidate();
        }

        private void panel_comp_Click(object sender, EventArgs e)
        {
            if (e != null) statics.compressor = !statics.compressor;

            Byte[] txb = new Byte[2];
            txb[0] = 9;
            txb[1] = (Byte)(statics.compressor?1:0); // compression factor
            Udp.UdpSendData(txb);

            panel_comp.Invalidate();
        }

        private void panel_comp_Paint(object sender, PaintEventArgs e)
        {
            using (Bitmap bm = new Bitmap(Properties.Resources.comp_on))
                using (Bitmap bminact = new Bitmap(Properties.Resources.comp_off))
                    drawButtonPanel(e.Graphics, statics.compressor, bm, bminact);
        }

        private void panel_copyTtoR_Click(object sender, EventArgs e)
        {
            statics.RXoffset = statics.TXoffset;
            statics.RXTXoffset = 0;
            sendAndRefreshRXTXoffset();
            panel_copyTtoR.Invalidate();
        }

        private void panel_rxfilter_Paint(object sender, PaintEventArgs e)
        {
            switch (statics.rxfilter)
            {
                case 0:
                    using (Bitmap bm = new Bitmap(Properties.Resources.rx_filter_1))
                        drawBitmap(e.Graphics, bm);
                    break;
                case 1:
                    using (Bitmap bm = new Bitmap(Properties.Resources.rx_filter_18))
                        drawBitmap(e.Graphics, bm);
                    break;
                case 2:
                    using (Bitmap bm = new Bitmap(Properties.Resources.rx_filter_27))
                        drawBitmap(e.Graphics, bm);
                    break;
                case 3:
                    using (Bitmap bm = new Bitmap(Properties.Resources.rx_filter_36))
                        drawBitmap(e.Graphics, bm);
                    break;
            }
        }

        private void panel_txfilter_Paint(object sender, PaintEventArgs e)
        {
            switch (statics.txfilter)
            {
                case 0:
                    using (Bitmap bm = new Bitmap(Properties.Resources.tx_filter_1))
                        drawBitmap(e.Graphics, bm);
                    break;
                case 1:
                    using (Bitmap bm = new Bitmap(Properties.Resources.tx_filter_18))
                        drawBitmap(e.Graphics, bm);
                    break;
                case 2:
                    using (Bitmap bm = new Bitmap(Properties.Resources.tx_filter_22))
                        drawBitmap(e.Graphics, bm);
                    break;
                case 3:
                case 4:
                    using (Bitmap bm = new Bitmap(Properties.Resources.tx_filter_27))
                        drawBitmap(e.Graphics, bm);
                    break;
            }
        }

        private void panel_rxfilter_Click(object sender, EventArgs e)
        {
            if (e != null) if (++statics.rxfilter > 3) statics.rxfilter = 0;

            Byte[] txb = new Byte[2];
            txb[0] = 12;
            txb[1] = (Byte)statics.rxfilter;
            Udp.UdpSendData(txb);

            panel_rxfilter.Invalidate();
        }

        private void panel_txfilter_Click(object sender, EventArgs e)
        {
            if (e != null) if (++statics.txfilter > 3) statics.txfilter = 0;

            Byte[] txb = new Byte[2];
            txb[0] = 13;
            txb[1] = (Byte)statics.txfilter;
            Udp.UdpSendData(txb);

            panel_txfilter.Invalidate();
        }

        private void panel_audioloop_Paint(object sender, PaintEventArgs e)
        {
            using (Bitmap bm = new Bitmap(Properties.Resources.audioloop))
                using (Bitmap bminact = new Bitmap(Properties.Resources.audioloop_inact))
                    drawButtonPanel(e.Graphics, statics.audioloop, bm, bminact);
        }

        private void panel_rfloop_Paint(object sender, PaintEventArgs e)
        {
            using (Bitmap bm = new Bitmap(Properties.Resources.rfloop))
                using (Bitmap bminact = new Bitmap(Properties.Resources.rfloop_inact))
                    drawButtonPanel(e.Graphics, statics.rfloop, bm, bminact);
        }

        private void panel_audioloop_Click(object sender, EventArgs e)
        {
            statics.audioloop = !statics.audioloop;
            if (statics.audioloop && statics.rfloop)
            {
                panel_rfloop_Click(null, null);
            }

            Byte[] txb = new Byte[2];
            txb[0] = 3;
            txb[1] = (Byte)(statics.audioloop ? 1 : 0);

            Udp.UdpSendData(txb);
            panel_audioloop.Invalidate();
            panel_rfloop.Invalidate();
        }

        private void panel_rfloop_Click(object sender, EventArgs e)
        {
            statics.rfloop = !statics.rfloop;
            if (statics.audioloop && statics.rfloop)
            {
                panel_audioloop_Click(null, null);
            }

            statics.ptt = statics.rfloop;
            panel1.Invalidate();
            setPTT(statics.ptt);

            Byte[] txb = new Byte[2];
            txb[0] = 5;
            txb[1] = (Byte)(statics.rfloop ? 1 : 0);

            Udp.UdpSendData(txb);
            panel_rfloop.Invalidate();
            panel_audioloop.Invalidate();
        }

        private void panel_pavucontrol_Click(object sender, EventArgs e)
        {
            statics.StartMixer(true);
        }

        static Pen cline = new Pen(Brushes.Yellow, 2);
        private void panel_rxline_Paint(object sender, PaintEventArgs e)
        {
            int x = statics.RXoffset / 500;
            x = x * panel_rxline.Width / 1120;
            //Console.WriteLine("pp " + x);
            using (Graphics gr = e.Graphics)
            {
                gr.DrawLine(cline, panel_rxline.Width / 2, panel_rxline.Height, x, 0);
            }
        }

        private void panel_sync_Paint(object sender, PaintEventArgs e)
        {
            // size 28 x 18 px
        }


        private void panel_beaconlock_Paint(object sender, PaintEventArgs e)
        {
            using (Graphics gr = e.Graphics)
            {
                if (statics.beaconlock)
                {
                    using (Bitmap bm = new Bitmap(Properties.Resources._lock))
                    {
                        gr.FillRectangle(Brushes.Gray, 0, 0, panel_beaconlock.Width, panel_beaconlock.Height);
                        gr.DrawImage(bm, 0, 0);
                    }
                }
                else
                {
                    using (Bitmap bm = new Bitmap(Properties.Resources.lock_open))
                    {
                        gr.FillRectangle(Brushes.Gray, 0, 0, panel_beaconlock.Width, panel_beaconlock.Height);
                        gr.DrawImage(bm, 0, 0);
                    }
                }
            }

            Byte[] txb = new Byte[2];
            txb[0] = 16;
            txb[1] = (Byte)(statics.beaconlock ? 1 : 0);
            Udp.UdpSendData(txb);

            panel_qrg.Invalidate();
        }

        private void panel_beaconlock_Click(object sender, EventArgs e)
        {
            statics.beaconlock = !statics.beaconlock;
            panel_beaconlock.Invalidate();
        }

        private void panel_sync_Click(object sender, EventArgs e)
        {
            Form_reference fr = new Form_reference();
            fr.Show();
        }

        private void panel_switchbandplan_Click(object sender, EventArgs e)
        {
            if (++statics.bandplan_mode >= 5) statics.bandplan_mode = 0;
            panel_bandplan.Invalidate();
        }

        private void panel_screen_Click(object sender, EventArgs e)
        {
            int ws = statics.windowsize;
            Form_screen fs = new Form_screen();
            fs.ShowDialog();
            if(ws != statics.windowsize)
            {
                scaleElements();
                Udp.UpdateSize();
            }
        }

        private void panel_save_Click(object sender, EventArgs e)
        {
            statics.lastRXoffset = statics.RXoffset;
            statics.lastTXoffset = statics.TXoffset;
        }
        private void panel_recall_Click(object sender, EventArgs e)
        {
            statics.RXoffset = statics.lastRXoffset;
            statics.TXoffset = statics.lastTXoffset;
            panel_qrg.Invalidate();
            sendAndRefreshRXTXoffset();
        }

        private void panel_testtone_Click(object sender, EventArgs e)
        {
            Byte[] txb = new Byte[1];
            txb[0] = 22;
            Udp.UdpSendData(txb);
        }

        private void panel_testtone_Paint(object sender, PaintEventArgs e)
        {
            if(statics.sendtone == 1)
                e.Graphics.DrawImage(Properties.Resources.waveactive,0,0);
            else
                e.Graphics.DrawImage(Properties.Resources.wave, 0, 0);
        }
    }

    class DoubleBufferedPanel : Panel 
    { 
        public DoubleBufferedPanel() : base() 
        {
            // double buffering crashes under windows
            OperatingSystem osversion = System.Environment.OSVersion;
            if (osversion.VersionString.Contains("indow"))
                statics.ostype = 0; // Win$
            else
            {
                statics.ostype = 1; // Linux
                DoubleBuffered = true;
            }
        }
    }
}
